Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

Artikel bakal mangpaat pikeun jalma anu:

  • terang naon Cert Klién sareng ngartos naha éta peryogi websockets dina Safari mobile;
  • Abdi hoyong nyebarkeun ladenan wéb ka sakumpulan jalma anu terbatas atanapi ngan ukur ka kuring sorangan;
  • nyangka yén sagalana geus dipigawé ku batur, sarta hayang nyieun dunya saeutik leuwih merenah tur aman.

Sajarah websockets dimimitian ngeunaan 8 sababaraha taun ka pengker. Saméméhna, métode anu dipaké dina bentuk requests http panjang (sabenerna réspon): panyungsi pamaké dikirim pamundut ka server na waited pikeun ngajawab hiji hal, sanggeus respon eta disambungkeun deui sarta antosan. Tapi lajeng websockets mucunghul.

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

Sababaraha taun ka pengker, urang ngembangkeun palaksanaan urang sorangan dina PHP murni, nu teu bisa maké requests HTTPS, saprak ieu lapisan link. Teu lila pisan, ampir kabéh pangladén wéb diajar pikeun proksi requests ngaliwatan https jeung ngarojong sambungan: upgrade.

Nalika ieu kajantenan, websockets janten ampir layanan standar pikeun aplikasi SPA, sabab kumaha merenah éta nyadiakeun eusi ka pamaké dina prakarsa server (nepikeun pesen ti pamaké séjén atawa ngundeur versi anyar tina hiji gambar, dokumen, presentasi. yén batur ayeuna ngédit).

Sanaos Sertipikat Klién parantos lami-lami, éta tetep kirang didukung, sabab nyiptakeun seueur masalah nalika nyobian jalan-jalan. Jeung (jigana: slightly_smiling_face: ) Éta naha panyungsi ios (sadayana iwal Safari) teu hayang make eta sarta menta ti toko sertipikat lokal. Sertipikat gaduh seueur kaunggulan dibandingkeun sareng login / pass atanapi konci ssh atanapi nutup palabuhan anu diperyogikeun ngalangkungan firewall. Tapi éta sanés perkawis ieu.

Dina ios, prosedur pikeun masang sertipikat cukup saderhana (henteu tanpa spésifik), tapi sacara umum dilakukeun dumasar kana petunjuk, anu seueur pisan dina Internét sareng anu ngan ukur sayogi pikeun browser Safari. Hanjakalna, Safari henteu terang kumaha ngagunakeun Client Сert pikeun sockets wéb, tapi aya seueur petunjuk dina Internét ngeunaan cara ngadamel sertipikat sapertos kitu, tapi dina prakna ieu henteu tiasa dicapai.

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

Pikeun ngartos websockets, kami nganggo rencana ieu: masalah / hipotésis / solusi.

masalahna: euweuh rojongan pikeun sockets web nalika requests proxying sumberdaya nu ditangtayungan ku sertipikat klien dina browser mobile Safari pikeun ios sarta aplikasi sejenna nu geus diaktipkeun rojongan sertipikat.

Hipotesis:

  1. Kasebut nyaéta dimungkinkeun pikeun ngonpigurasikeun iwal misalna pikeun ngagunakeun sertipikat (nyaho yén bakal aya euweuh) kana websockets sumberdaya internal / éksternal proxied.
  2. Pikeun websockets, anjeun tiasa ngadamel sambungan unik, aman tur defensible ngagunakeun sesi samentara anu dihasilkeun salila pamundut browser normal (non-websocket).
  3. Sesi samentawis tiasa dilaksanakeun nganggo hiji pangladén wéb proxy (modul sareng fungsi anu diwangun wungkul).
  4. Token sési samentawis parantos dilaksanakeun salaku modul Apache siap-siap.
  5. Token sési samentara bisa dilaksanakeun ku logis ngarancang struktur interaksi.

kaayaan katempo sanggeus palaksanaan.

Tujuan: manajemén jasa jeung infrastruktur kudu diaksés tina handphone on ios tanpa program tambahan (kayaning VPN), ngahiji jeung aman.

Tujuan tambahan: ngahemat waktos sareng sumber / lalu lintas telepon (sababaraha jasa tanpa sockets wéb ngahasilkeun pamundut anu teu perlu) kalayan pangiriman eusi anu langkung gancang dina Internét sélulér.

Kumaha mariksa?

1. Kaca bubuka:

— например, https://teamcity.yourdomain.com в мобильном браузере Safari (доступен также в десктопной версии) — вызывает успешное подключение к веб-сокетам.
— например, https://teamcity.yourdomain.com/admin/admin.html?item=diagnostics&tab=webS…— показывает ping/pong.
— например, https://rancher.yourdomain.com/p/c-84bnv:p-vkszd/workload/deployment:danidb:ph…-> viewlogs — показывает логи контейнера.

2. Atawa dina konsol pamekar:

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

Uji hipotésis:

1. Kasebut nyaéta dimungkinkeun pikeun ngonpigurasikeun iwal misalna pikeun make sertipikat (nyaho yén bakal aya euweuh) kana web sockets internal / sumberdaya éksternal proxied.

2 solusi kapanggih di dieu:

a) Dina tingkat

<Location sock*> SSLVerifyClient optional </Location>
<Location /> SSLVerifyClient require </Location>

ngarobah tingkat aksés.

Metoda ieu boga nuances handap:

  • Verifikasi sertipikat lumangsung sanggeus pamundut ka sumberdaya proxied, nyaeta, pos pamundut sasalaman. Ieu ngandung harti yén proxy bakal muka heula lajeng neukteuk off pamundut ka layanan nu ditangtayungan. Ieu goréng, tapi teu kritis;
  • Dina protokol http2. Masih dina draf, sareng produsén browser henteu terang kumaha nerapkeunana #info ngeunaan tls1.3 http2 post sasalaman (henteu tiasa dianggo ayeuna) Laksanakeun RFC 8740 "Nganggo TLS 1.3 sareng HTTP / 2";
  • Henteu écés kumaha ngahijikeun prosés ieu.

b) Dina tingkat dasar, ngidinan ssl tanpa sertipikat.

SSLVerifyClient merlukeun => SSLVerifyClient opsional, tapi ieu ngurangan tingkat kaamanan server proxy, saprak sambungan sapertos bakal diolah tanpa sertipikat. Nanging, anjeun tiasa nampik aksés kana jasa anu diproksi ku diréktif ieu:

RewriteEngine        on
RewriteCond     %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteRule     .? - [F]
ErrorDocument 403 "You need a client side certificate issued by CAcert to access this site"

Inpormasi anu langkung lengkep tiasa dipendakan dina tulisan ngeunaan ssl: Auténtikasi Sertipikat Klién Apache Server

Duanana pilihan diuji, pilihan "b" dipilih pikeun versatility sarta kasaluyuan jeung protokol http2.

Pikeun ngalengkepan verifikasi hipotésis ieu, peryogi seueur ékspérimén sareng konfigurasi; desain di handap ieu diuji:

lamun = merlukeun = nulis balik

Hasilna nyaéta desain dasar di handap ieu:

SSLVerifyClient optional
RewriteEngine on
RewriteCond %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule     .? - [F]
#ErrorDocument 403 "You need a client side certificate issued by CAcert to access this site"

#websocket for safari without cert auth
<If "%{SSL:SSL_CLIENT_VERIFY} != 'SUCCESS'">
<If "%{HTTP:Upgrade} = 'websocket'">
...
    #замещаем авторизацию по владельцу сертификата на авторизацию по номеру протокола
    SSLUserName SSl_PROTOCOL
</If>
</If>

Ningali otorisasina anu tos aya ku anu gaduh sertipikat, tapi kalayan sertipikat anu leungit, kuring kedah nambihan pamilik sertipikat anu henteu aya dina bentuk salah sahiji variabel anu sayogi SSl_PROTOCOL (gaganti SSL_CLIENT_S_DN_CN), langkung rinci dina dokuméntasi:

Modul Apache mod_ssl

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

2. Pikeun websockets, anjeun tiasa ngadamel sambungan unik, aman tur ditangtayungan ngagunakeun sesi samentara anu dihasilkeun salila normal (non-websocket) pamundut browser.

Dumasar pangalaman saméméhna, anjeun kudu nambahan hiji bagian tambahan kana konfigurasi dina urutan nyiapkeun tokens samentara pikeun sambungan stop kontak web salila pamundut biasa (non-web).

#подготовка передача себе Сookie через пользовательский браузер
<If "%{SSL:SSL_CLIENT_VERIFY} = 'SUCCESS'">
<If "%{HTTP:Upgrade} != 'websocket'">
Header set Set-Cookie "websocket-allowed=true; path=/; Max-Age=100"
</If>
</If>

#проверка Cookie для установления веб-сокет соединения
<source lang="javascript">
<If "%{SSL:SSL_CLIENT_VERIFY} != 'SUCCESS'">
<If "%{HTTP:Upgrade} = 'websocket'">
#check for exists cookie

#get and check
SetEnvIf Cookie "websocket-allowed=(.*)" env-var-name=$1

#or rewrite rule
RewriteCond %{HTTP_COOKIE} !^.*mycookie.*$

#or if
<If "%{HTTP_COOKIE} =~ /(^|; )cookie-names*=s*some-val(;|$)/ >
</If

</If>
</If>

Tés nunjukkeun yén éta tiasa dianggo. Kasebut nyaéta dimungkinkeun pikeun nransper Cookies ka diri ngaliwatan browser pamaké.

3. Sesi samentara bisa dilaksanakeun ngagunakeun hiji proxy web server (ngan diwangun-di modul jeung fungsi).

Sakumaha anu urang terangkeun sateuacana, Apache ngagaduhan seueur fungsi inti anu ngamungkinkeun anjeun nyiptakeun konstruksi kondisional. Nanging, urang peryogi alat pikeun ngajagi inpormasi nalika aya dina browser pangguna, ku kituna urang netepkeun naon anu kedah disimpen sareng kunaon, sareng naon fungsi anu bakal kami anggo:

  • Urang peryogi token anu teu tiasa gampang dikodekeun.
  • Urang kudu token nu geus obsolescence diwangun kana eta jeung kamampuhan pikeun pariksa obsolescence on server.
  • Urang peryogi token anu bakal dikaitkeun sareng anu gaduh sertipikat.

Ieu peryogi fungsi hashing, uyah, sareng tanggal pikeun umur token. Dumasar kana dokuméntasi Babasan dina Apache HTTP Server urang gaduh eta sadayana out of the box sha1 jeung %{TIME}.

Hasilna nyaéta desain ieu:

#нет сертификата, и обращение к websocket
<If "%{SSL:SSL_CLIENT_VERIFY} != 'SUCCESS'">
<If "%{HTTP:Upgrade} = 'websocket'">
    SetEnvIf Cookie "zt-cert-sha1=([^;]+)" zt-cert-sha1=$1
    SetEnvIf Cookie "zt-cert-uid=([^;]+)" zt-cert-uid=$1
    SetEnvIf Cookie "zt-cert-date=([^;]+)" zt-cert-date=$1

#только так можно работать с переменными, полученными в env-ах в этот момент времени, более они нигде не доступны для функции хеширования (по отдельности можно, но не вместе, да и ещё с хешированием)
    <RequireAll>
        Require expr %{sha1:salt1%{env:zt-cert-date}salt3%{env:zt-cert-uid}salt2} == %{env:zt-cert-sha1}
        Require expr %{env:zt-cert-sha1} =~ /^.{40}$/
    </RequireAll>
</If>
</If>

#есть сертификат, запрашивается не websocket
<If "%{SSL:SSL_CLIENT_VERIFY} = 'SUCCESS'">
<If "%{HTTP:Upgrade} != 'websocket'">
    SetEnvIf Cookie "zt-cert-sha1=([^;]+)" HAVE_zt-cert-sha1=$1

    SetEnv zt_cert "path=/; HttpOnly;Secure;SameSite=Strict"
#Новые куки ставятся, если старых нет
    Header add Set-Cookie "expr=zt-cert-sha1=%{sha1:salt1%{TIME}salt3%{SSL_CLIENT_S_DN_CN}salt2};%{env:zt_cert}" env=!HAVE_zt-cert-sha1
    Header add Set-Cookie "expr=zt-cert-uid=%{SSL_CLIENT_S_DN_CN};%{env:zt_cert}" env=!HAVE_zt-cert-sha1
    Header add Set-Cookie "expr=zt-cert-date=%{TIME};%{env:zt_cert}" env=!HAVE_zt-cert-sha1
</If>
</If>

Tujuanana geus kahontal, tapi aya masalah jeung server obsolescence (anjeun tiasa ngagunakeun Cookie taun heubeul), nu hartina tokens, sanajan aman pikeun pamakéan internal, teu aman pikeun pamakéan industri (massa).

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

4. tokens sési samentara geus dilaksanakeun salaku modul Apache siap-dijieun.

Hiji masalah signifikan tetep ti Iteration saméméhna - henteu mampuh ngadalikeun sepuh token.

Kami milarian modul siap-siap anu ngalakukeun ieu, dumasar kana kecap: Apache token json two factor auth

Sumuhun, aya modul siap-dijieun, tapi aranjeunna sadayana dihijikeun ka lampah husus sarta mibanda artefak dina bentuk ngamimitian sési jeung Cookies tambahan. Hartina, henteu sakedap.
Butuh waktu lima jam pikeun milarian, anu henteu masihan hasil anu konkret.

5. tokens sési samentara bisa dilaksanakeun ku logis ngarancang struktur interaksi.

modul siap-dijieun teuing kompléks, sabab urang ngan butuh sababaraha fungsi.

Kitu cenah, masalah tanggal nyaéta yén Apache diwangun-di fungsi teu ngidinan generating tanggal ti mangsa nu bakal datang, tur euweuh tambahan / pangurangan matematik dina fungsi diwangun-di nalika mariksa obsolescence.

Hartina, anjeun teu bisa nulis:

(%{env:zt-cert-date} + 30) > %{DATE}

Anjeun ngan bisa ngabandingkeun dua angka.

Nalika milarian solusi pikeun masalah Safari, kuring mendakan tulisan anu pikaresepeun: Ngamankeun HomeAssistant sareng sertipikat klien (jalan sareng Safari/ios)
Éta ngajelaskeun conto kode dina Lua pikeun Nginx, sareng anu, tétéla, seueur pisan ngulang logika bagian tina konfigurasi anu parantos kami laksanakeun, iwal ti ngagunakeun metode hmac salting pikeun hashing ( ieu teu kapanggih dina Apache).

Janten jelas yén Lua mangrupikeun basa kalayan logika anu jelas, sareng anjeun tiasa ngalakukeun anu saderhana pikeun Apache:

Sanggeus diajar bédana sareng Nginx sareng Apache:

Sareng fungsi anu sayogi ti produsén basa Lua:
22.1 - Kaping sareng Waktos

Kami mendakan cara pikeun nyetél variabel env dina file Lua leutik pikeun nyetél tanggal ka hareup pikeun ngabandingkeun sareng anu ayeuna.

Ieu mangrupikeun skrip Lua anu sederhana:

require 'apache2'

function handler(r)
    local fmt = '%Y%m%d%H%M%S'
    local timeout = 3600 -- 1 hour

    r.notes['zt-cert-timeout'] = timeout
    r.notes['zt-cert-date-next'] = os.date(fmt,os.time()+timeout)
    r.notes['zt-cert-date-halfnext'] = os.date(fmt,os.time()+ (timeout/2))
    r.notes['zt-cert-date-now'] = os.date(fmt,os.time())

    return apache2.OK
end

Sareng ieu kumaha sadayana dianggo dina total, kalayan optimasi jumlah Cookies sareng ngagantian token nalika satengah waktos sateuacan Cookie (token) lami tamat:

SSLVerifyClient optional

#LuaScope thread
#generate event variables zt-cert-date-next
LuaHookAccessChecker /usr/local/etc/apache24/sslincludes/websocket_token.lua handler early

#запрещаем без сертификата что-то ещё, кроме webscoket
RewriteEngine on
RewriteCond %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule     .? - [F]
#ErrorDocument 403 "You need a client side certificate issued by CAcert to access this site"

#websocket for safari without certauth
<If "%{SSL:SSL_CLIENT_VERIFY} != 'SUCCESS'">
<If "%{HTTP:Upgrade} = 'websocket'">
    SetEnvIf Cookie "zt-cert=([^,;]+),([^,;]+),[^,;]+,([^,;]+)" zt-cert-sha1=$1 zt-cert-date=$2 zt-cert-uid=$3

    <RequireAll>
        Require expr %{sha1:salt1%{env:zt-cert-date}salt3%{env:zt-cert-uid}salt2} == %{env:zt-cert-sha1}
        Require expr %{env:zt-cert-sha1} =~ /^.{40}$/
        Require expr %{env:zt-cert-date} -ge %{env:zt-cert-date-now}
    </RequireAll>
   
    #замещаем авторизацию по владельцу сертификата на авторизацию по номеру протокола
    SSLUserName SSl_PROTOCOL
    SSLOptions -FakeBasicAuth
</If>
</If>

<If "%{SSL:SSL_CLIENT_VERIFY} = 'SUCCESS'">
<If "%{HTTP:Upgrade} != 'websocket'">
    SetEnvIf Cookie "zt-cert=([^,;]+),[^,;]+,([^,;]+)" HAVE_zt-cert-sha1=$1 HAVE_zt-cert-date-halfnow=$2
    SetEnvIfExpr "env('HAVE_zt-cert-date-halfnow') -ge %{TIME} && env('HAVE_zt-cert-sha1')=~/.{40}/" HAVE_zt-cert-sha1-found=1

    Define zt-cert "path=/;Max-Age=%{env:zt-cert-timeout};HttpOnly;Secure;SameSite=Strict"
    Define dates_user "%{env:zt-cert-date-next},%{env:zt-cert-date-halfnext},%{SSL_CLIENT_S_DN_CN}"
    Header set Set-Cookie "expr=zt-cert=%{sha1:salt1%{env:zt-cert-date-next}sal3%{SSL_CLIENT_S_DN_CN}salt2},${dates_user};${zt-cert}" env=!HAVE_zt-cert-sha1-found
</If>
</If>

SetEnvIfExpr "env('HAVE_zt-cert-date-halfnow') -ge %{TIME} && env('HAVE_zt-cert-sha1')=~/.{40}/" HAVE_zt-cert-sha1-found=1
работает,

а так работать не будет
SetEnvIfExpr "env('HAVE_zt-cert-date-halfnow') -ge  env('zt-cert-date-now') && env('HAVE_zt-cert-sha1')=~/.{40}/" HAVE_zt-cert-sha1-found=1 

Kusabab LuaHookAccessChecker ngan bakal diaktipkeun saatos cék aksés dumasar kana inpormasi ieu ti Nginx.

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

Tumbu ka sumber gambaran.

Hiji deui.

Sacara umum, henteu masalah dina urutan naon diréktif ditulis dina konfigurasi Apache (sigana ogé Nginx), sabab dina tungtungna sagalana bakal disusun dumasar kana urutan pamundut ti pamaké, nu pakait jeung skéma pikeun ngolah. naskah Lua.

Parantosan:

Kaayaan katingali saatos palaksanaan (tujuan):
manajemén jasa jeung infrastruktur sadia tina handphone on ios tanpa program tambahan (VPN), ngahiji jeung aman.

Tujuanana geus kahontal, sockets web dianggo tur mibanda tingkat kaamanan teu kurang ti sertipikat.

Kumaha urang di ZeroTech disambungkeun Apple Safari sarta sertipikat klien kalawan websockets

sumber: www.habr.com

Tambahkeun komentar