Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Gotar dê ji bo kesên ku:

  • dizane Client Cert çi ye û fêm dike ku çima ew hewceyê websocketên li ser Safari-ya mobîl e;
  • Ez dixwazim karûbarên malperê ji xeleka sînorkirî ya mirovan re an tenê ji xwe re biweşînim;
  • difikire ku her tişt jixwe ji hêla kesek ve hatî çêkirin, û dixwaze dinyayê hinekî hêsantir û ewledar bike.

Dîroka websockets nêzîkî 8 sal berê dest pê kir. Berê, rêbaz di forma daxwazên dirêj ên http de (bi rastî bersiv) dihatin bikar anîn: geroka bikarhêner daxwazek ji serverê re şand û li bendê bû ku ew tiştek bersiv bide, piştî bersivê ew dîsa ve girêda û li bendê bû. Lê paşê websocket xuya bûn.

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Çend sal berê, me di PHP-ya paqij de pêkanîna xwe pêşxist, ku nikare daxwazên https bikar bîne, ji ber ku ev qata girêdanê ye. Demek berê, hema hema hemî serverên malperê fêr bûn ku daxwazên proxy li ser https û piştgirî bidin girêdan: nûvekirin.

Gava ku ev çêbû, websocket hema hema ji bo serîlêdanên SPA-yê bû karûbarê xwerû, ji ber ku çiqas hêsan e ku meriv bi însiyatîfa serverê naverokê ji bikarhêner re peyda bike (peyamek ji bikarhênerek din veguhezîne an guhertoyek nû ya wêne, belge, pêşkêşî dakêşîne. ku kesekî din niha diguherîne) .

Her çend Sertîfîkaya Xerîdar ji demek dirêj ve li dora xwe ye, ew hîn jî kêm piştgirî dimîne, ji ber ku ew gava ku hewl dide ku wê derbas bike gelek pirsgirêkan diafirîne. Û (dibe ku :slightly_smiling_face: ) ji ber vê yekê gerokên IOS-ê (hemû ji bilî Safari) naxwazin wê bikar bînin û ji dikana sertîfîkaya herêmî daxwaz bikin. Sertîfîka li gorî bişkojkên têketinê/derbasbûnê an ssh an girtina benderên pêwîst bi navgîniya dîwarê agir ve gelek avantajên xwe hene. Lê ev ne li ser vê yekê ye.

Li ser iOS, prosedûra sazkirina sertîfîkayê pir hêsan e (ne bê taybetmendî), lê bi gelemperî ew li gorî rêwerzanan tê kirin, yên ku li ser Înternetê gelek hene û yên ku tenê ji bo geroka Safari hene. Mixabin, Safari nizane ku meriv çawa Client Сert ji bo soketên malperê bikar tîne, lê li ser Înternetê gelek rêwerz hene ku meriv çawa sertîfîkayek wusa biafirîne, lê di pratîkê de ev yek ne pêkan e.

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Ji bo fêmkirina websockets, me plana jêrîn bikar anî: pirsgirêk / hîpotez / çareserî.

Pirsgirêk: Di dema prokskirina daxwazên çavkaniyên ku ji hêla sertîfîkaya xerîdar a li ser geroka mobîl a Safari ve ji bo IOS û sepanên din ên ku piştgiriya sertîfîkayê çalak kirine ve têne parastin, ji bo soketên malperê piştgirî tune.

Hîpotez:

  1. Mimkun e ku meriv îstîsnayek weha mîheng bike da ku sertîfîkayan bikar bîne (dizanin ku dê tune be) li ser tevnên çavkaniyên pêvekirî yên hundurîn / derveyî.
  2. Ji bo websocketan, hûn dikarin bi karanîna danişînên demkî yên ku di dema daxwaznameyek gerokek normal (ne-websocket) de têne çêkirin, pêwendiyek bêhempa, ewledar û parastî çêbikin.
  3. Danişînên demkî dikarin bi karanîna yek serverek webê ya proxy (tenê modul û fonksiyonên çêkirî) bêne bicîh kirin.
  4. Nîşaneyên danişîna demkî berê wekî modulên Apache yên amade hatine bicîh kirin.
  5. Nîşaneyên danişîna demkî bi sêwirana mentiqî ya strukturên danûstendinê ve têne bicîh kirin.

Rewşa xuya piştî pêkanîna.

Armanca xebatê: rêveberiya karûbar û binesaziyê divê ji têlefonek desta ya li ser IOS bêyî bernameyên zêde (wek VPN), yekgirtî û ewledar be.

Armanca zêde: teserûfkirina dem û çavkaniyan / seyrûsefera têlefonê (hin karûbarên bêyî soketên malperê daxwazên nehewce çêdikin) bi radestkirina bilez a naverokê li ser Înterneta mobîl.

Meriv çawa kontrol dike?

1. Vekirina rûpelan:

— например, 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. An jî di konsolê pêşdebiran de:

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Testkirina hîpotezê:

1. Ji bo bikaranîna sertîfîkayan (dizanin ku dê tune nebe) li ser soketên tevneyên çavkaniyên pêvekirî yên hundurîn/derve ve gengaz e ku meriv îstîsnayek weha mîheng bike.

2 çareserî li vir hatin dîtin:

a) Di astê de

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

asta gihîştinê biguherînin.

Vê rêbazê hûrgelên jêrîn hene:

  • Verastkirina sertîfîkayê piştî daxwazek ji çavkaniya proxidî re pêk tê, ango, piştî daxwazkirina destanan. Ev tê vê wateyê ku proxy dê pêşî bar bike û dûv re jî daxwaza karûbarê parastî qut bike. Ev xerab e, lê ne krîtîk e;
  • Di protokola http2 de. Ew hîn jî di pêşnûmeyê de ye, û çêkerên gerok nizanin ka meriv wê çawa bicîh bîne #info derbarê tls1.3 http2 post handshake (niha naxebite) RFC 8740 "Bikaranîna TLS 1.3 bi HTTP/2" re bicîh bikin;
  • Ne diyar e ka meriv çawa vê pêvajoyê bike yek.

b) Di astek bingehîn de, destûr bide ssl bêyî sertîfîkayê.

SSLVerifyClient hewce dike => SSLVerifyClient vebijarkî ye, lê ev asta ewlehiyê ya pêşkêşkara proxy kêm dike, ji ber ku pêwendiyek wusa dê bêyî sertîfîkayê were xebitandin. Lêbelê, hûn dikarin bi dîrektîfa jêrîn gihandina karûbarên proxidî jî red bikin:

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"

Agahiyên berfirehtir di gotara ssl de têne dîtin: Nasnameya Sertîfîkaya Xerîdar a Apache Server

Her du vebijark hatin ceribandin, vebijarka "b" ji ber piralî û lihevhatina wê ya bi protokola http2 re hate hilbijartin.

Ji bo temamkirina verastkirina vê hîpotezê, bi veavakirinê re gelek ceribandin hatin girtin; sêwiranên jêrîn hatin ceribandin:

heke = hewce bike = ji nû ve binivîsîne

Encam sêwirana bingehîn a jêrîn e:

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>

Li gorî destûrnameya heyî ji hêla xwediyê sertîfîkayê ve, lê digel sertîfîkayek wenda, min neçar ma ku xwedanek sertîfîkayek neheyî di forma yek ji guhêrbarên berdest SSl_PROTOCOL (li şûna SSL_CLIENT_S_DN_CN) zêde bikim, hûrguliyên bêtir di belgeyê de:

Modula Apache mod_ssl

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

2. Ji bo websocketan, hûn dikarin pêwendiyek yekta, ewledar û parastî bi karanîna danişînên demkî yên ku di dema daxwaznameyek gerokek normal (ne-websocket) de têne çêkirin çêbikin.

Li ser bingeha ezmûna berê, hûn hewce ne ku beşek din li mîhengê zêde bikin da ku di dema daxwazek birêkûpêk (ne-socket) de nîşanekên demkî ji bo girêdanên soketa malperê amade bikin.

#подготовка передача себе С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>

Testê nîşan da ku ew dixebite. Mimkûn e ku hûn bi riya geroka bikarhêner ve Cookies ji xwe re veguhezînin.

3. Danişînên demkî dikarin bi karanîna yek serverek proxy (tenê modul û fonksiyonên çêkirî) bêne bicîh kirin.

Wekî ku me berê fêhm kir, Apache xwedan gelek fonksiyonên bingehîn e ku destûrê dide we ku hûn avahiyên şertî biafirînin. Lêbelê, pêdivî ye ku em agahdariya xwe biparêzin dema ku ew di geroka bikarhêner de ye, ji ber vê yekê em destnîşan dikin ka çi hilînin û çima, û kîjan fonksiyonên çêkirî yên ku em ê bikar bînin:

  • Pêdiviya me bi tokenek heye ku bi hêsanî neyê deşîfrekirin.
  • Pêdiviya me bi tokenek heye ku kevinbûn di nav xwe de çêkiriye û jêhatîbûna kontrolkirina kevneperestiya li ser serverê heye.
  • Pêdiviya me bi tokenek heye ku dê bi xwediyê sertîfîkayê re têkildar be.

Ji bo vê yekê fonksiyonek hashing, xwê, û tarîxek pêdivî ye ku token temen bibe. Li ser bingeha belgeyê Gotinên di Apache HTTP Server me hemûyan ji sindoqê sha1 û %{TIME} heye.

Encam ev dîzam bû:

#нет сертификата, и обращение к 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>

Armanc gihîştiye, lê pirsgirêk bi kevinbûna serverê re hene (hûn dikarin Cookie-yek-salî bikar bînin), ev tê vê wateyê ku nîşanek, her çend ji bo karanîna hundurîn ewle be jî, ji bo karanîna pîşesaziyê (girseyî) ne ewle ne.

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

4. Nîşaneyên danişîna demkî berê wekî modulên Apache yên amade hatine bicîh kirin.

Pirsgirêkek girîng ji dubarekirina berê ma - nebûna kontrolkirina pîrbûna token.

Em li modulek amade digerin ku vê yekê dike, li gorî peyvan: apache token json du faktor auth

Erê, modulên amade hene, lê ew hemî bi çalakiyên taybetî ve girêdayî ne û di forma destpêkirina danişînê û Cookiesên din de huner hene. Yanî ne ji bo demekê.
Ji bo lêgerîna me XNUMX saetan derbas bû, lê encamek berbiçav derneket.

5. Nîşaneyên danişîna demkî bi sêwirana mentiqî ya strukturên danûstendinan dikarin bêne bicîh kirin.

Modulên amade pir tevlihev in, ji ber ku em tenê çend fonksiyonan hewce ne.

Wusa ku tê gotin, pirsgirêka tarîxê ev e ku fonksiyonên çêkirî yên Apache rê nadin ku tarîxek ji pêşerojê were hilberandin, û di fonksiyonên çêkirî de dema ku kevinbûnê kontrol dikin de zêdekirin/kêmkirinek matematîkî tune.

Ango hûn nikarin binivîsin:

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

Hûn dikarin tenê du hejmaran bidin ber hev.

Dema ku li çareseriyek ji bo pirsgirêka Safari digeriyam, min gotarek balkêş dît: Ewlekirina HomeAssistant bi sertîfîkayên xerîdar (bi Safari / iOS re dixebite)
Ew mînakek kodê li Lua-yê ji bo Nginx vedibêje, û ku, wekî ku derket holê, mantiqa wê beşa veavakirinê ya ku me berê bicîh kiriye, pir dubare dike, ji bilî karanîna rêbaza xwêkirina hmac ji bo haşkirinê ( ev di Apache de nehat dîtin).

Eşkere bû ku Lua zimanek bi mantiqek zelal e, û gengaz e ku meriv ji bo Apache tiştek hêsan bike:

Dema ku cûdahiya bi Nginx û Apache re lêkolîn kir:

Û fonksiyonên berdest ji hilberînerê zimanê Lua:
22.1 - Dîrok û Dem

Me rêyek dît ku em guhêrbarên env di pelek piçûk a Lua de bicîh bikin da ku tarîxek ji paşerojê veqetînin da ku bi ya heyî re bidin berhev.

Ev e ku skrîptek Lua ya hêsan dixuye:

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

Û bi vî awayî ew hemî bi tevahî dixebite, bi xweşbînkirina hejmara Cookie-yê û veguheztina tokenê dema ku nîvê demê tê berî ku Cookie (token) kevn biqede:

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 

Ji ber ku LuaHookAccessChecker dê tenê piştî kontrolên gihîştinê li ser bingeha vê agahdariya ji Nginx were çalak kirin.

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Girêdana çavkaniyê Wêne.

Tiştek din.

Bi gelemperî, ne girîng e ku rêwerz bi kîjan rêzê di veavakirina Apache (dibe ku di heman demê de Nginx) têne nivîsandin, ji ber ku di dawiyê de dê her tişt li gorî rêza daxwaznameya bikarhêner, ku bi pilana ji bo pêvajoyê re têkildar e, were rêz kirin. Nivîsarên Lua.

Qedandinî:

Rewşa xuya ya piştî bicîhkirinê (armanc):
rêveberiya karûbar û binesaziyê ji têlefonek desta ya li ser IOS bêyî bernameyên zêde (VPN), yekgirtî û ewledar peyda dibe.

Armanc gihîştiye, soketên webê dixebitin û astek ewlehiyê ne ji sertîfîkayê kêmtir in.

Çawa me li ZeroTech sertîfîkayên Apple Safari û xerîdar bi websocketan ve girêda

Source: www.habr.com

Add a comment