Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Artikulli do të jetë i dobishëm për ata që:

  • e di se çfarë është Client Cert dhe e kupton pse i duhen uebsocketet në Safari celular;
  • Do të doja të publikoja shërbime në internet për një rreth të kufizuar njerëzish ose vetëm për veten time;
  • mendon se gjithçka është bërë tashmë nga dikush, dhe do të donte ta bënte botën pak më të përshtatshme dhe më të sigurt.

Historia e websocketeve filloi rreth 8 vjet më parë. Më parë, metodat përdoreshin në formën e kërkesave të gjata http (në të vërtetë përgjigjet): shfletuesi i përdoruesit dërgoi një kërkesë në server dhe priste që ai të përgjigjej diçka, pas përgjigjes u lidh përsëri dhe priti. Por më pas u shfaqën foletë në internet.

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Disa vite më parë, ne zhvilluam implementimin tonë në PHP të pastër, i cili nuk mund të përdorë kërkesat https, pasi kjo është shtresa e lidhjes. Jo shumë kohë më parë, pothuajse të gjithë serverët e uebit mësuan të proksojnë kërkesat përmes https dhe të mbështesin lidhjen: përditësimin.

Kur ndodhi kjo, uebsocketet u bënë pothuajse shërbimi i paracaktuar për aplikacionet SPA, sepse sa i përshtatshëm është t'i ofroni përmbajtje përdoruesit me iniciativën e serverit (transmetoni një mesazh nga një përdorues tjetër ose shkarkoni një version të ri të një imazhi, dokumenti, prezantimi që dikush tjetër është duke e redaktuar aktualisht) .

Edhe pse Certifikata e Klientit ka ekzistuar për mjaft kohë, ajo ende mbetet e dobët e mbështetur, pasi krijon shumë probleme kur përpiqet ta anashkalojë atë. Dhe (ndoshta :slightly_smiling_face: ) kjo është arsyeja pse shfletuesit IOS (të gjithë përveç Safari) nuk duan ta përdorin atë dhe ta kërkojnë nga dyqani lokal i certifikatave. Certifikatat kanë shumë përparësi në krahasim me çelësat login/pass ose ssh ose mbylljen e portave të nevojshme përmes një muri zjarri. Por nuk bëhet fjalë për këtë.

Në iOS, procedura për instalimin e një certifikate është mjaft e thjeshtë (jo pa specifika), por në përgjithësi bëhet sipas udhëzimeve, nga të cilat ka shumë në internet dhe të cilat janë të disponueshme vetëm për shfletuesin Safari. Fatkeqësisht, Safari nuk di të përdorë Client Сert për prizat në internet, por ka shumë udhëzime në internet se si të krijoni një certifikatë të tillë, por në praktikë kjo është e paarritshme.

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Për të kuptuar websocketet, ne përdorëm planin e mëposhtëm: problem/hipotezë/zgjidhje.

problem: nuk ka mbështetje për prizat e uebit kur përkthehen kërkesat për burimet që mbrohen nga një certifikatë klienti në shfletuesin celular Safari për IOS dhe aplikacione të tjera që kanë aktivizuar mbështetjen e certifikatës.

Hipotezat:

  1. Është e mundur të konfigurohet një përjashtim i tillë për të përdorur certifikata (duke e ditur që nuk do të ketë asnjë) në uebsqet e burimeve të brendshme/të jashtme të proksiuara.
  2. Për websocketet, ju mund të krijoni një lidhje unike, të sigurt dhe të mbrojtur duke përdorur sesione të përkohshme që krijohen gjatë një kërkese normale (jo-websocket) të shfletuesit.
  3. Sesionet e përkohshme mund të zbatohen duke përdorur një server proxy (vetëm modulet dhe funksionet e integruara).
  4. Shenjat e sesionit të përkohshëm tashmë janë zbatuar si module të gatshme Apache.
  5. Shenjat e sesionit të përkohshëm mund të zbatohen duke dizajnuar logjikisht strukturën e ndërveprimit.

Gjendja e dukshme pas zbatimit.

Objektiv: menaxhimi i shërbimeve dhe infrastrukturës duhet të jetë i aksesueshëm nga një telefon celular në IOS pa programe shtesë (si VPN), i unifikuar dhe i sigurt.

Objektivi shtesë: duke kursyer kohë dhe burime/trafik telefoni (disa shërbime pa priza ueb gjenerojnë kërkesa të panevojshme) me shpërndarje më të shpejtë të përmbajtjes në internetin celular.

Si të kontrolloni?

1. Hapja e faqeve:

— например, 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. Ose në tastierën e zhvilluesit:

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Testimi i hipotezave:

1. Është e mundur të konfigurohet një përjashtim i tillë për të përdorur certifikata (duke e ditur që nuk do të ketë asnjë) në prizat e internetit të burimeve të brendshme/të jashtme të proksiuara.

Këtu u gjetën 2 zgjidhje:

a) Në nivel

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

ndryshoni nivelin e aksesit.

Kjo metodë ka nuancat e mëposhtme:

  • Verifikimi i certifikatës ndodh pas një kërkese për burimin e proksiuar, domethënë, një shtrëngim duarsh pas kërkesës. Kjo do të thotë që përfaqësuesi fillimisht do të ngarkojë dhe më pas do të ndërpresë kërkesën për shërbimin e mbrojtur. Kjo është e keqe, por jo kritike;
  • Në protokollin http2. Është ende në draft dhe prodhuesit e shfletuesit nuk dinë ta zbatojnë atë #info rreth tls1.3 http2 post shtrëngimin e duarve (nuk funksionon tani) Zbatoni RFC 8740 "Using TLS 1.3 with HTTP/2";
  • Nuk është e qartë se si të unifikohet ky përpunim.

b) Në një nivel bazë, lejo ssl pa certifikatë.

SSLVerifyClient kërkon => SSLVerifyClient opsionale, por kjo zvogëlon nivelin e sigurisë së serverit proxy, pasi një lidhje e tillë do të përpunohet pa certifikatë. Megjithatë, ju mund të refuzoni më tej aksesin në shërbimet proksi me direktivën e mëposhtme:

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"

Informacion më të detajuar mund të gjendet në artikullin rreth ssl: Autentifikimi i certifikatës së klientit të serverit Apache

Të dy opsionet u testuan, opsioni "b" u zgjodh për shkathtësinë dhe pajtueshmërinë e tij me protokollin http2.

Për të përfunduar verifikimin e kësaj hipoteze, u deshën shumë eksperimente me konfigurimin; u testuan modelet e mëposhtme:

nëse = kërkoj = rishkruaj

Rezultati është dizajni bazë i mëposhtëm:

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>

Duke marrë parasysh autorizimin ekzistues nga zotëruesi i certifikatës, por me një certifikatë që mungon, më duhej të shtoja një zotërues joekzistent certifikate në formën e një prej variablave të disponueshëm SSl_PROTOCOL (në vend të SSL_CLIENT_S_DN_CN), më shumë detaje në dokumentacion:

Moduli Apache mod_ssl

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

2. Për foletë uebi, mund të krijoni një lidhje unike, të sigurt dhe të mbrojtur duke përdorur sesione të përkohshme që krijohen gjatë një kërkese të shfletuesit normal (jo të rrjetit).

Bazuar në përvojën e mëparshme, ju duhet të shtoni një seksion shtesë në konfigurim në mënyrë që të përgatisni argumente të përkohshme për lidhjet e prizave në ueb gjatë një kërkese të rregullt (jo fole në internet).

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

Testimi tregoi se funksionon. Është e mundur të transferoni Cookies tek vetja përmes shfletuesit të përdoruesit.

3. Sesionet e përkohshme mund të zbatohen duke përdorur një server proxy (vetëm modulet dhe funksionet e integruara).

Siç zbuluam më herët, Apache ka mjaft funksione thelbësore që ju lejojnë të krijoni konstruksione të kushtëzuara. Megjithatë, ne kemi nevojë për mjete për të mbrojtur informacionin tonë ndërsa është në shfletuesin e përdoruesit, kështu që ne vendosim se çfarë të ruajmë dhe pse, dhe cilat funksione të integruara do të përdorim:

  • Ne kemi nevojë për një shenjë që nuk mund të deshifrohet lehtë.
  • Ne kemi nevojë për një shenjë që ka vjetërsinë e integruar dhe aftësinë për të kontrolluar vjetërsinë në server.
  • Na duhet një shenjë që do të lidhet me zotëruesin e certifikatës.

Kjo kërkon një funksion hashing, një kripë dhe një datë për të vjetëruar tokenin. Në bazë të dokumentacionit Shprehjet në serverin Apache HTTP ne i kemi të gjitha jashtë kutisë sha1 dhe %{TIME}.

Rezultati ishte ky dizajn:

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

Qëllimi është arritur, por ka probleme me vjetërsimin e serverit (mund të përdorni një Cookie një vjeçare), që do të thotë se tokenet, megjithëse të sigurta për përdorim të brendshëm, janë të pasigurt për përdorim industrial (masiv).

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

4. Shenjat e sesionit të përkohshëm tashmë janë implementuar si module të gatshme Apache.

Një problem i rëndësishëm mbeti nga përsëritja e mëparshme - pamundësia për të kontrolluar plakjen e shenjave.

Ne po kërkojmë një modul të gatshëm që e bën këtë, sipas fjalëve: apache token json two factor auth

Po, ka module të gatshme, por të gjitha janë të lidhura me veprime specifike dhe kanë artefakte në formën e fillimit të një sesioni dhe Cookies shtesë. Kjo është, jo për një kohë.
Na u deshën pesë orë për të kërkuar, gjë që nuk dha një rezultat konkret.

5. Shenjat e sesionit të përkohshëm mund të zbatohen duke dizajnuar logjikisht strukturën e ndërveprimeve.

Modulet e gatshme janë shumë komplekse, sepse na duhen vetëm disa funksione.

Thënë kjo, problemi me datën është se funksionet e integruara të Apache nuk lejojnë gjenerimin e një date nga e ardhmja dhe nuk ka asnjë mbledhje/zbritje matematikore në funksionet e integruara kur kontrollohet për vjetërsi.

Kjo do të thotë, ju nuk mund të shkruani:

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

Mund të krahasoni vetëm dy numra.

Ndërsa kërkoja një zgjidhje për problemin Safari, gjeta një artikull interesant: Sigurimi i HomeAssistant me certifikatat e klientit (funksionon me Safari/iOS)
Ai përshkruan një shembull të kodit në Lua për Nginx, dhe i cili, siç doli, përsërit shumë logjikën e asaj pjese të konfigurimit që kemi zbatuar tashmë, me përjashtim të përdorimit të metodës hmac salting për hash ( kjo nuk u gjet në Apache).

U bë e qartë se Lua është një gjuhë me logjikë të qartë dhe është e mundur të bëhet diçka e thjeshtë për Apache:

Duke studiuar ndryshimin me Nginx dhe Apache:

Dhe funksionet e disponueshme nga prodhuesi i gjuhës Lua:
22.1 – Data dhe ora

Ne gjetëm një mënyrë për të vendosur variabla env në një skedar të vogël Lua në mënyrë që të caktojmë një datë nga e ardhmja për t'u krahasuar me atë aktuale.

Kështu duket një skenar i thjeshtë Lua:

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

Dhe kështu funksionon e gjitha në total, me optimizimin e numrit të Cookies dhe zëvendësimin e tokenit kur gjysma e kohës vjen përpara skadimit të Cookie (tokenit) të vjetër:

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 

Sepse LuaHookAccessChecker do të aktivizohet vetëm pas kontrolleve të aksesit bazuar në këtë informacion nga Nginx.

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Lidhja me burimin imazh.

Një tjetër pikë.

Në përgjithësi, nuk ka rëndësi se në çfarë rendi janë shkruar direktivat në konfigurimin Apache (ndoshta edhe Nginx), pasi në fund gjithçka do të renditet në bazë të renditjes së kërkesës nga përdoruesi, i cili korrespondon me skemën e përpunimit. Skriptet Lua.

Përfundimi:

Gjendja e dukshme pas zbatimit (qëllimi):
menaxhimi i shërbimeve dhe infrastrukturës ofrohet nga një telefon celular në IOS pa programe shtesë (VPN), i unifikuar dhe i sigurt.

Qëllimi është arritur, prizat në internet funksionojnë dhe kanë një nivel sigurie jo më pak se një certifikatë.

Si ne në ZeroTech lidhëm Apple Safari dhe certifikatat e klientëve me foletë në internet

Burimi: www.habr.com

Shto një koment