πŸ•΅ ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π°Ρ‚Π°ΠΊ XSS ΠΈ способов ΠΈΡ… ослаблСния

ПониманиС мСТсайтового скриптинга ΠΈ способов Π±ΠΎΡ€ΡŒΠ±Ρ‹ с Π½ΠΈΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ Π²Π΅Π±-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ. Π­Ρ‚ΠΎ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· самых распространСнных Π²ΠΈΠ΄ΠΎΠ² уязвимостСй – Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΠΈ часто проводят Π°Ρ‚Π°ΠΊΠΈ XSS для ΠΊΡ€Π°ΠΆΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Π½Π°Ρ€ΡƒΡˆΠ΅Π½ΠΈΡ работоспособности сСрвисов.

ΠŸΠ΅Ρ€Π΅Π²ΠΎΠ΄ публикуСтся с сокращСниями, Π°Π²Ρ‚ΠΎΡ€ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΉ ΡΡ‚Π°Ρ‚ΡŒΠΈ Russel Jones.

ΠœΠ΅ΠΆΡΠ°ΠΉΡ‚ΠΎΠ²Ρ‹ΠΉ скриптинг (XSS) – это Π°Ρ‚Π°ΠΊΠ°, которая позволяСт JavaScript Ρ‡Π΅Ρ€Π΅Π· ΠΎΠ΄ΠΈΠ½ сайт Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π΄Ρ€ΡƒΠ³ΠΈΠΌ. XSS интСрСсСн Π½Π΅ ΠΈΠ·-Π·Π° тСхничСской слоТности, Π° скорСС ΠΏΠΎΡ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ эксплуатируСт Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠ· основных ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠΎΠ² бСзопасности Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠ² ΠΈ ΠΈΠ·-Π·Π° ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠΉ распространСнности.

Background

Π˜Π·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ ВсСмирная ΠŸΠ°ΡƒΡ‚ΠΈΠ½Π° прСдставляла собой Π½Π°Π±ΠΎΡ€ статичСских Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² HTML, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Π» ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒ для просмотра ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌΠΈ. По ΠΌΠ΅Ρ€Π΅ развития Π˜Π½Ρ‚Π΅Ρ€Π½Π΅Ρ‚Π° возрастали ΠΈ трСбования ΠΊ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π»ΠΎ ΠΊ появлСнию JavaScript ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ² cookie: скрипты Π½ΡƒΠΆΠ½Ρ‹ для интСрактивности Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, Π° cookies – Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ ΠΌΠΎΠ³Π»ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ Π΅Π³ΠΎ состояниС.

ПоявлСниС этих возмоТностСй ΠΏΡ€ΠΈΠ²Π΅Π»ΠΎ ΠΊ Ρ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΡŽΡ‚ HTML, Π½ΠΎ ΠΈ Π²ΠΌΠ΅Ρ‰Π°ΡŽΡ‚ Π² памяти Π² качСствС API для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² прСдставлСниС, Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΠΎΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π½ΠΎΠΉ модСлью Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π° (DOM). DOM ΠΏΡ€Π΅Π΄Π»Π°Π³Π°Π΅Ρ‚ Π΄Ρ€Π΅Π²ΠΎΠ²ΠΈΠ΄Π½ΡƒΡŽ структуру Ρ‚Π΅Π³ΠΎΠ² HTML, Π° Ρ‚Π°ΠΊΠΆΠ΅ доступ ΠΊ Ρ„Π°ΠΉΠ»Π°ΠΌ cookie для получСния состояния. Π‘ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ модСль ΠΏΡ€Π΅Π²Ρ€Π°Ρ‚ΠΈΠ»Π°ΡΡŒ ΠΈΠ· ΠΏΡ€Π΅Π΄Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π½ΠΎΠΉ прСимущСствСнно для чтСния структуры Π² структуру read-write, ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎΠΌΡƒ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³Ρƒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.

Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄, Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Π»ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ контСкст выполнСния для ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ Π½Π° JavaScript. ΠŸΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ°, которая Π±Ρ‹Π»Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½Π°, называСтся Same-Origin ΠΈ ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ являСтся ΠΎΠ΄Π½ΠΈΠΌ ΠΈΠ· Ρ„ΡƒΠ½Π΄Π°ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²ΠΎΠ² бСзопасности Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π°. Π˜Π·Π½Π°Ρ‡Π°Π»ΡŒΠ½ΠΎ Π² Π½Π΅ΠΉ ΡƒΡ‚Π²Π΅Ρ€ΠΆΠ΄Π°Π»ΠΎΡΡŒ, Ρ‡Ρ‚ΠΎ JavaScript Π² ΠΎΠ΄Π½ΠΎΠΌ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊ собствСнному DOM ΠΈ ΠΊ DOM Π΄Ρ€ΡƒΠ³ΠΈΡ… Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² с Ρ‚Π΅ΠΌ ΠΆΠ΅ происхоТдСниСм. ПозТС, ΠΊΠΎΠ³Π΄Π° Π±Ρ‹Π» Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ XMLHttpRequest ΠΈ Fetch, появилась модифицированная вСрсия Same-Origin. Π­Ρ‚ΠΈ API Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π²Ρ‹Π΄Π°Π²Π°Ρ‚ΡŒ запросы ΠΊ Π»ΡŽΠ±ΠΎΠΌΡƒ источнику, ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΡ‚Π²Π΅Ρ‚ Π½Π° запросы ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ источника.

Π§Ρ‚ΠΎ ΠΆΠ΅ Ρ‚Π°ΠΊΠΎΠ΅ происхоТдСниС? Π­Ρ‚ΠΎ ΠΊΠΎΡ€Ρ‚Π΅ΠΆ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π°, ΠΈΠΌΠ΅Π½ΠΈ хоста ΠΈ ΠΏΠΎΡ€Ρ‚Π° Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°.
Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 1: ΠšΠΎΡ€Ρ‚Π΅ΠΆ ΠΈΠ· схСмы, хоста ΠΈ ΠΏΠΎΡ€Ρ‚Π° этого URL-адрСса.
https://www.example.com:443/app
^^^^^   ^^^^^^^^^^^^^^^ ^^^
Scheme  Host            Port
Рис. 1: Π˜Π»Π»ΡŽΡΡ‚Ρ€Π°Ρ†ΠΈΡ Same-Origin Π² дСйствии. JavaScript Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π° www.evil.com ΠΈ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ DOM Π½Π° www.example.com.

ΠŸΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° Same-Origin ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ ΡΠΌΡΠ³Ρ‡Π°Ρ‚ΡŒ Π°Ρ‚Π°ΠΊΠΈ Π½Π° статичСскиС сайты, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π½Π° рисункС Π²Ρ‹ΡˆΠ΅. Однако с Π°Ρ‚Π°ΠΊΠ°ΠΌΠΈ Π½Π° динамичСскиС рСсурсы, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‰ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π²ΠΎΠ΄, ситуация Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ слоТнСС ΠΈΠ·-Π·Π° смСшивания ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, которая позволяСт Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΡƒ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ Π²Π²ΠΎΠ΄ Π² исходном Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π΅.

Атаки XSS ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π±Ρ‹Π²Π°ΡŽΡ‚ Ρ‚Ρ€Π΅Ρ… Π²ΠΈΠ΄ΠΎΠ²: Ρ€Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ, Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹ΠΌΠΈ ΠΈ основанными Π½Π° DOM.

Π Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΈ Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹Π΅ XSS-Π°Ρ‚Π°ΠΊΠΈ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠΈΠ°Π»ΡŒΠ½ΠΎ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΏΠΎΠ»Π°Π³Π°ΡŽΡ‚ΡΡ Π½Π° врСдоносный Π²Π²ΠΎΠ΄, отправляСмый Π½Π° Π±Π΅ΠΊΠ΅Π½Π΄ ΠΈ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΠΉ этот Π²Π²ΠΎΠ΄ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ сСрвСр. Π Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ XSS ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π²ΠΎΠ·Π½ΠΈΠΊΠ°ΡŽΡ‚ Π² Π²ΠΈΠ΄Π΅ Π·Π»ΠΎΠ½Π°ΠΌΠ΅Ρ€Π΅Π½Π½ΠΎ созданной Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΠΎΠΌ ссылки, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π·Π°Ρ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΆΠ΅Ρ€Ρ‚Π²Π°. Π₯Ρ€Π°Π½ΠΈΠΌΡ‹Π΅ XSS происходят, ΠΊΠΎΠ³Π΄Π° Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ врСдоносный Π²Π²ΠΎΠ΄. Атаки Π½Π° основС DOM ΠΎΡ‚Π»ΠΈΡ‡Π°ΡŽΡ‚ΡΡ Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ происходят ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π° сторонС ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ врСдоносный Π²Π²ΠΎΠ΄, ΠΌΠ°Π½ΠΈΠΏΡƒΠ»ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ DOM.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

Π Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ Π°Ρ‚Π°ΠΊΠΈ XSS

НиТС ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ простоС Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Go, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΎΡ‚Ρ€Π°ΠΆΠ°Π΅Ρ‚ свой Π²Π²ΠΎΠ΄ (Π΄Π°ΠΆΠ΅ Ссли это врСдоносный скрипт) ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, сохранив Π΅Π³ΠΎ Π² Ρ„Π°ΠΉΠ»Π΅ xss1.go ΠΈ запустив go run xss1.go.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 3: ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π²Π΅Π±-прилоТСния с Ρ€Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ (ΠΎΡ‚Ρ€Π°ΠΆΠ΅Π½Π½ΠΎΠΉ) XSS-Π°Ρ‚Π°ΠΊΠΎΠΉ.
package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-XSS-Protection", "0")

    messages, ok := r.URL.Query()["message"]
    if !ok {
       messages = []string{"hello, world"}
    }
    fmt.Fprintf(w, "<html><p>%v</p></html>", messages[0])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ XSS-Π°Ρ‚Π°ΠΊΡƒ, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ уязвимому URL-адрСсу Π½ΠΈΠΆΠ΅.

http://localhost:8080?message=<script>alert(1)</script>

ВзглянитС Π½Π° источник: сСрвСр Π²Π΅Ρ€Π½ΡƒΠ» Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ выглядит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²ΠΎ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ 4. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΊΠ°ΠΊ смСшСниС ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΠ»ΠΎ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΡ‚ΠΈ этой Π°Ρ‚Π°ΠΊΠ΅.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 4: ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π²Ρ‹Π²ΠΎΠ΄Π° уязвимого для XSS Π²Π΅Π±-прилоТСния.
<html>
  <p>
    <script>alert(1)</script>
  </p>
</html>

Π­Ρ‚ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ Π½Π΅ΠΏΡ€Π°Π²Π΄ΠΎΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹ΠΌ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π·Π°Ρ‰ΠΈΡ‚Π° XSS Π±Ρ‹Π»Π° явно ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Π°. Π­Ρ‚Π° Π΅Π΅ Ρ„ΠΎΡ€ΠΌΠ° основана Π½Π° эвристикС с ΠΎΠ±Ρ…ΠΎΠ΄Π½Ρ‹ΠΌΠΈ путями для Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠ². Она Π±Ρ‹Π»Π° ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π΅Π½Π° для создания кроссбраузСрных ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ², ΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽΡ‰ΠΈΡ… основныС ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ XSS-Π°Ρ‚Π°ΠΊ. НСкоторыС Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ эту Π·Π°Ρ‰ΠΈΡ‚Ρƒ: Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² Google Chrome 78 ΠΈ Π²Ρ‹ΡˆΠ΅ Π²Π°ΠΌ Π½Π΅ понадобится строка w.Header().Set("X-XSS-Protection", "0"), Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π°Ρ‚Π°ΠΊΠ° сработала.

Π₯Ρ€Π°Π½ΠΈΠΌΡ‹Π΅ XSS-Π°Ρ‚Π°ΠΊΠΈ

Π₯Ρ€Π°Π½ΠΈΠΌΡ‹Π΅ XSS-Π°Ρ‚Π°ΠΊΠΈ ΠΏΠΎΡ…ΠΎΠΆΠΈ Π½Π° Ρ€Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅, Π½ΠΎ пэйлоад поступаСт ΠΈΠ· Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° Π΄Π°Π½Π½Ρ‹Ρ…, Π° Π½Π΅ ΠΈΠ· Π²Π²ΠΎΠ΄Π° нСпосрСдствСнно. НапримСр, Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π·Π»ΠΎΠ²Ρ€Π΅Π΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π·Π°Ρ‚Π΅ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Π½ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΌΡƒ ΡŽΠ·Π΅Ρ€Ρƒ.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ простой Ρ‡Π°Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ этот Π²ΠΈΠ΄ Π°Ρ‚Π°ΠΊ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ»Π΅ xss2.go ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ go run xss2.go.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 5: Π₯ранимая XSS-Π°Ρ‚Π°ΠΊΠ°.
package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"
	"sync"
)

var db []string
var mu sync.Mutex

var tmpl = `
<form action="/save">
  Message: <input name="message" type="text"><br>
  <input type="submit" value="Submit">
</form>
%v
`

func saveHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	r.ParseForm()
	messages, ok := r.Form["message"]
	if !ok {
		http.Error(w, "missing message", 500)
	}

	db = append(db, messages[0])

	http.Redirect(w, r, "/", 301)
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("X-XSS-Protection", "0")
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	var sb strings.Builder
	sb.WriteString("<ul>")
	for _, message := range db {
		sb.WriteString("<li>" + message + "</li>")
	}
	sb.WriteString("</ul>")

	fmt.Fprintf(w, tmpl, sb.String())
}

func main() {
	http.HandleFunc("/", viewHandler)
	http.HandleFunc("/save", saveHandler)
	log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ Π°Ρ‚Π°ΠΊΡƒ XSS, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС http://localhost:8080 ΠΈ Π²Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС <script>alert(1);</script>.

Атака дСлится Π½Π° Π΄Π²Π΅ Ρ„Π°Π·Ρ‹:

  • ΠΏΠ΅ΠΉΠ»ΠΎΠ°Π΄ сохраняСтся Π² Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ Π΄Π°Π½Π½Ρ‹Ρ… Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ storeHandler;
  • ΠΊΠΎΠ³Π΄Π° страница визуализируСтся Π²ΠΎ ViewHandler, ΠΏΠ΅ΠΉΠ»ΠΎΠ°Π΄ добавляСтся ΠΊ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ Π΄Π°Π½Π½Ρ‹ΠΌ.

XSS-Π°Ρ‚Π°ΠΊΠΈ Π½Π° основС DOM

Π’Π°ΠΊΠΈΠ΅ Π°Ρ‚Π°ΠΊΠΈ Π½Π΅ связаны с Π±Π΅ΠΊΠ΅Π½Π΄ΠΎΠΌ ΠΈ происходят ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π° сторонС ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°. Они интСрСсны Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ соврСмСнныС Π²Π΅Π±-прилоТСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°ΡŽΡ‚ Π»ΠΎΠ³ΠΈΠΊΡƒ ΠΊ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Ρƒ, Π° Π°Ρ‚Π°ΠΊΠΈ происходят, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ ΠΌΠ°Π½ΠΈΠΏΡƒΠ»ΠΈΡ€ΡƒΠ΅Ρ‚ DOM. Π₯ΠΎΡ€ΠΎΡˆΠ΅ΠΉ Π½ΠΎΠ²ΠΎΡΡ‚ΡŒΡŽ для Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΠΎΠ² являСтся Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ DOM ΠΈΠΌΠ΅Π΅Ρ‚ ΡˆΠΈΡ€ΠΎΠΊΠΈΠΉ спСктр способов эксплуатации, Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ популярными ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΡΠ²Π»ΡΡŽΡ‚ΡΡ innerHTML ΠΈ document.write.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΎΠ±ΡΠ»ΡƒΠΆΠΈΠ²Π°ΡŽΡ‰Π΅Π³ΠΎ статичСский ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚ Π²Π΅Π±-прилоТСния. Код Ρ‚ΠΎΡ‚ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ ΠΈ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ с Ρ€Π΅Ρ„Π»Π΅ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ XSS, Π½ΠΎ здСсь Π°Ρ‚Π°ΠΊΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π½Π° сторонС ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ»Π΅ xss3.go ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ go run xss3.go.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 6: ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π²Π΅Π±-прилоТСния с XSS-Π°Ρ‚Π°ΠΊΠΎΠΉ Π½Π° основС DOM.
package main

import (
    "fmt"
    "log"
    "net/http"
)

const content = `

<html>
   <head>
       <script>
          window.onload = function() {
             var params = new URLSearchParams(window.location.search);
             p = document.getElementById("content")
             p.innerHTML = params.get("message")
	     };
       </script>
   </head>
   <body>
       <p id="content"></p>
   </body>
</html>
`

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-XSS-Protection", "0")
    fmt.Fprintf(w, content)
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ эту Π°Ρ‚Π°ΠΊΡƒ, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС http://localhost:8080/?message="<img src=1 onerror=alert(1);/>". ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Π²Π΅ΠΊΡ‚ΠΎΡ€ Π°Ρ‚Π°ΠΊΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ отличаСтся ΠΈ innerHTML Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ скрипт Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΎΠ½ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ HTML-элСмСнты, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π°Ρ‚Π΅ΠΌ выполнят ΠΊΠΎΠ΄ Π½Π° JavaScript. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ добавляСтся элСмСнт image, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ запускаСт скрипт ΠΏΡ€ΠΈ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΠΈ ошибки (ΠΎΠ½Π° всСгда появляСтся, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ подставляСт Π½Π΅Π²Π΅Ρ€Π½Ρ‹ΠΉ источник).

Если Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ элСмСнт скрипта, придСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΡ€ΠΈΠ΅ΠΌΠ½ΠΈΠΊ XSS. Π—Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ элСмСнт script ΠΈΠ· Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π° 6 элСмСнтом script ΠΈΠ· Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π° 7 ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ссылкС: http://localhost:8080/?message="<script>alert(1);</script>". Атака сработаСт, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ document.write ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ элСмСнты скрипта Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 7: Π•Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π°Ρ‚Π°ΠΊΠΈ XSS Π½Π° основС DOM.
<script>
   window.onload = function() {
      var params = new URLSearchParams(window.location.search);
      document.open();
      document.write(params.get("message"));
      document.close();
   };
</script>

БвязанныС направлСния Π°Ρ‚Π°ΠΊ

Π₯отя ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΈΡ… Π½Π΅ Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ Π°Ρ‚Π°ΠΊΠ°ΠΌΠΈ XSS, сущСствуСт нСсколько связанных Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠΉ, ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… стоит ΡƒΠΏΠΎΠΌΡΠ½ΡƒΡ‚ΡŒ.

Content-type

ВсСму Π²ΠΈΠ½ΠΎΠΉ Π½Π΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Π°Ρ настройка Ρ‚ΠΈΠΏΠ° содСрТимого ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ² HTTP. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠΈΠ·ΠΎΠΉΡ‚ΠΈ ΠΊΠ°ΠΊ Π½Π° ΡƒΡ€ΠΎΠ²Π½Π΅ Π±Π΅ΠΊΠ΅Π½Π΄Π° (ΠΎΡ‚Π²Π΅Ρ‚ ΠΈΠΌΠ΅Π΅Ρ‚ Π½Π΅Π²Π΅Ρ€Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΎΠ² Content-Type), Ρ‚Π°ΠΊ ΠΈ ΠΏΡ€ΠΈ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ΅ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° ΠΏΡ€ΠΎΡΠ½ΠΈΡ„Ρ„Π΅Ρ€ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ MIME. Internet Explorer Π±Ρ‹Π» особСнно восприимчив ΠΊ этому, ΠΈ классичСским ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ являСтся слуТба Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ: Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ JavaScript вмСсто ΠΊΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠΈ. Π‘Ρ€Π°ΡƒΠ·Π΅Ρ€ Π²ΠΈΠ΄ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Ρ‚ΠΈΠΏ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π° Π±Ρ‹Π» установлСн Π½Π° image/jpg, Π½ΠΎ ΠΏΠ΅ΠΉΠ»ΠΎΠ°Π΄ содСрТит скрипт – ΠΎΠ½ выполняСтся, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ Π°Ρ‚Π°ΠΊΠ΅ XSS.

Urlschemes

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Ρ‚ΠΈΠΏ Π°Ρ‚Π°ΠΊΠΈ – Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· URL со схСмой JavaScript. ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²ΠΈΠΌ Π²Π΅Π±-сайт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ позволяСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ†Π΅Π»ΡŒ ссылки, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²ΠΎ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ 8. Π’ этом случаС Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ смоТСт ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ URL, Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‰ΠΈΠΉ Π½Π΅ΠΊΠΈΠΉ JavaScript с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ нашСй схСмы.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ этот Ρ‚ΠΈΠΏ Π°Ρ‚Π°ΠΊΠΈ, ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ»Π΅ xss4.go, Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ go run xss4.go ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΏΠΎ ссылкС http://localhost:8080?link=javascript:alert(1).

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 8: XSS-Π°Ρ‚Π°ΠΊΠ°, ввСдСнная Ρ‡Π΅Ρ€Π΅Π· схСму URL-адрСсов.
package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-XSS-Protection", "0")

    links, ok := r.URL.Query()["link"]
    if !ok {
        messages = []string{"example.com"}
    }
    fmt.Fprintf(w, `<html><p><a href="%v">Next</p></html>`, links[0])
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}

ИзбавлСниС

Π•Π΄ΠΈΠ½ΠΎΠ³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π΄Π°Π½Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ Π½Π΅ сущСствуСт, ΠΈΠ½Π°Ρ‡Π΅ XSS Π½Π΅ Π±Ρ‹Π» Π±Ρ‹ Ρ‚Π°ΠΊΠΎΠΉ распространСнной ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠΎΠΉ. Π€ΡƒΠ½Π΄Π°ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Π°Ρ ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²Ρ‹Π·Π²Π°Π½Π° отсутствиСм раздСлСния ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠΎΠ΄ΠΎΠΌ ΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ. БмягчСниС послСдствий XSS ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ очистку Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… (Π½ΡƒΠΆΠ½ΠΎ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ Π½Π΅ содСрТат ΠΊΠΎΠ΄Π°), экранированиС Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… (ΠΎΠ½ΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄) ΠΈ Ρ€Π΅ΡΡ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€ΠΈΠ·Π°Ρ†ΠΈΡŽ прилоТСния Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΠ΄ загруТался ΠΈΠ· строго ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹Ρ… Ρ‚ΠΎΡ‡Π΅ΠΊ.

Валидация Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…

ΠŸΠ΅Ρ€Π²Π°Ρ линия Π·Π°Ρ‰ΠΈΡ‚Ρ‹ – ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…. Π£Π±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ ΠΈΡ… Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ соотвСтствуСт ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡ‹ΠΌ характСристикам – эдакий Π±Π΅Π»Ρ‹ΠΉ список, Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ отсутствиС Ρƒ прилоТСния возмоТности ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄.

Валидация Π΄Π°Π½Π½Ρ‹Ρ… – слоТная ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°. НС сущСствуСт ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ инструмСнта ΠΈΠ»ΠΈ Ρ‚Π΅Ρ…Π½ΠΈΠΊΠΈ для всСх ситуаций. Π›ΡƒΡ‡ΡˆΠ΅ всСго ΡΡ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΎ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π»ΠΎ ΠΎΡ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² ΠΏΡ€ΠΎΠ΄ΡƒΠΌΠ°Ρ‚ΡŒ Ρ‚ΠΈΠΏ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌΡ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ΅ мСсто, Π³Π΄Π΅ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π°Π·ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€.

Π₯ΠΎΡ€ΠΎΡˆΠΈΠΉ Ρ‚ΠΎΠ½ написания ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° Go состоит Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΈΠΌΠ΅Ρ‚ΡŒ Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ Π»ΠΎΠ³ΠΈΠΊΠΈ прилоТСния Π² ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°Ρ… запросов HTTP, Π° вмСсто этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡ… для Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…. Π—Π°Ρ‚Π΅ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ΡΡ Π² ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‰ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ структуру. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ запросов становятся простыми ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°ΡŽΡ‚ ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ΅ Ρ†Π΅Π½Ρ‚Ρ€Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ΅ располоТСниС для контроля ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΡΡ‚ΠΈ очистки Π΄Π°Π½Π½Ρ‹Ρ….

На Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ 9 ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ saveHandler для ΠΏΡ€ΠΈΠ΅ΠΌΠ° символов ASCII [A-Za-z\.].

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 9: ΠŸΡ€ΠΈΠΌΠ΅Ρ€ использования ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² HTTP-запросов для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ….
func saveHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	messages, ok := r.Form["message"]
	if !ok {
		http.Error(w, "missing message", 500)
	}

	re := regexp.MustCompile(`^[A-Za-z\\.]+$`)
	if re.Find([]byte(messages[0]))) == "" {
		http.Error(w, "invalid message", 500)
	}
  
	db.Append(messages[0])

	http.Redirect(w, r, "/", 301)
}

ΠœΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ это излишнСС бСспокойство, Π½ΠΎ Ρ‡Π°Ρ‚-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π³ΠΎΡ€Π°Π·Π΄ΠΎ большС, Ρ‡Π΅ΠΌ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ символов. МногиС ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅ΠΌΡ‹Π΅ прилоТСниями Π΄Π°Π½Π½Ρ‹Π΅ достаточно структурированы: адрСса, Π½ΠΎΠΌΠ΅Ρ€Π° Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½ΠΎΠ², ΠΏΠΎΡ‡Ρ‚ΠΎΠ²Ρ‹Π΅ индСксы ΠΈ Ρ‚ΠΎΠΌΡƒ ΠΏΠΎΠ΄ΠΎΠ±Π½Ρ‹Π΅ Π²Π΅Ρ‰ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Π½Ρ‹.

Π­ΠΊΡ€Π°Π½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ шаг – экранированиС Π²Ρ‹Π²ΠΎΠ΄Π°. Π’ случаС с нашим Ρ‡Π°Ρ‚ΠΎΠΌ всС ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½Π½ΠΎΠ΅ ΠΈΠ· Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π²ΠΊΠ»ΡŽΡ‡Π°Π»ΠΎΡΡŒ нСпосрСдствСнно Π² Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠΉ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚.

Одно ΠΈ Ρ‚ΠΎ ΠΆΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π³ΠΎΡ€Π°Π·Π΄ΠΎ бСзопаснСС (Π΄Π°ΠΆΠ΅ Ссли Π² Π½Π΅Π³ΠΎ Π±Ρ‹Π»Π° ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½Π° ΠΈΠ½ΡŠΠ΅ΠΊΡ†ΠΈΡ ΠΊΠΎΠ΄Π°), Ссли ΡΠΊΡ€Π°Π½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ всС нСбСзопасныС Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅. ИмСнно это Π΄Π΅Π»Π°Π΅Ρ‚ ΠΏΠ°ΠΊΠ΅Ρ‚ html/template Π² Go. ИспользованиС языка шаблонов ΠΈ контСкстно-зависимого синтаксичСского Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° для экранирования Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎ ΠΈΡ… Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ Π²Π΅Ρ€ΠΎΡΡ‚Π½ΠΎΡΡ‚ΡŒ выполнСния врСдоносного ΠΊΠΎΠ΄Π°.

НиТС ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования ΠΏΠ°ΠΊΠ΅Ρ‚Π° html/template. Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ„Π°ΠΉΠ»Π΅ xss5.go, Π° Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ go run xss5.go.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 10: ИспользованиС экранирования для устранСния Ρ…Ρ€Π°Π½ΠΈΠΌΡ‹Ρ… XSS-Π°Ρ‚Π°ΠΊ.
package main

import (
	"bytes"
	"html/template"
	"io"
	"log"
	"net/http"
	"sync"
)

var db []string
var mu sync.Mutex

var tmpl = `
<form action="/save">
  Message: <input name="message" type="text"><br>
  <input type="submit" value="Submit">
</form>
<ul>
{{range .}}
    <li>{{.}}</li>
{{end}}
</ul>`

func saveHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	r.ParseForm()
	messages, ok := r.Form["message"]
	if !ok {
		http.Error(w, "missing message", 500)
	}

	db = append(db, messages[0])

	http.Redirect(w, r, "/", 301)
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("X-XSS-Protection", "0")
	w.Header().Set("Content-Type", "text/html; charset=utf-8")

	t := template.New("view")

	t, err := t.Parse(tmpl)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	var buf bytes.Buffer

	err = t.Execute(&buf, db)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	io.Copy(w, &buf)
}

func main() {
	http.HandleFunc("/", viewHandler)
	http.HandleFunc("/save", saveHandler)
	log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
}

ΠžΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½ΡƒΡŽ Ρ€Π°Π½Π΅Π΅ Π°Ρ‚Π°ΠΊΡƒ XSS, пСрСйдя ΠΏΠΎ ссылкС http://localhost:8080 ΠΈ Π²Π²Π΅Π΄ΠΈΡ‚Π΅ <script>alert(1);</script>. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅ Π½Π΅ Π±Ρ‹Π»ΠΎ Π²Ρ‹Π·Π²Π°Π½ΠΎ.

ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ консоль Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° ΠΈ посмотритС Π½Π° элСмСнт li Π² DOM. Π˜Π½Ρ‚Π΅Ρ€Π΅Ρ ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ Π΄Π²Π° свойства: innerHTML ΠΈ innerText.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 11: ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° DOM ΠΏΡ€ΠΈ использовании экранирования.
innerHTML: "&lt;script&gt;alert(1);&lt;/script&gt;"
innerText: "<script>alert(1);</script>"

ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΊΠ°ΠΊ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ экранирования ΡƒΠ΄Π°Π»ΠΎΡΡŒ Ρ‡Π΅Ρ‚ΠΊΠΎ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΊΠΎΠ΄ ΠΈ Π΄Π°Π½Π½Ρ‹Π΅.

Content Security Policy

Content Security Policy (CSP) позволяСт Π²Π΅Π±-прилоТСниям ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡ‚ΡŒ Π½Π°Π±ΠΎΡ€ Π΄ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹Ρ… источников для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π° (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, скриптов). CSP ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для раздСлСния ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, ΠΎΡ‚ΠΊΠ°Π·Ρ‹Π²Π°ΡΡΡŒ ΠΎΡ‚ встроСнных скриптов ΠΈ загруТая ΠΈΡ… Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ· ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… источников.

НаписаниС CSP для Π½Π΅Π±ΠΎΠ»ΡŒΡˆΠΈΡ… Π°Π²Ρ‚ΠΎΠ½ΠΎΠΌΠ½Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ являСтся простой Π·Π°Π΄Π°Ρ‡Π΅ΠΉ – Π½Π°Ρ‡Π½ΠΈΡ‚Π΅ с ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠΈ, которая ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π·Π°ΠΏΡ€Π΅Ρ‰Π°Π΅Ρ‚ всС источники, Π° Π·Π°Ρ‚Π΅ΠΌ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚Π΅ нСбольшой ΠΈΡ… Π½Π°Π±ΠΎΡ€. Однако Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ эффСктивный CSP для Π±ΠΎΠ»ΡŒΡˆΠΈΡ… сайтов ΡƒΠΆΠ΅ Π½Π΅ Ρ‚Π°ΠΊ просто. Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ сайт Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚ ΠΈΠ· Π²Π½Π΅ΡˆΠ½ΠΈΡ… источников, CSP раздуваСтся ΠΈ становится Π³Ρ€ΠΎΠΌΠΎΠ·Π΄ΠΊΠΈΠΌ. НСкоторыС Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΡΠ΄Π°ΡŽΡ‚ΡΡ ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρƒ unsafe-inline, ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Ρ€Π°Π·Ρ€ΡƒΡˆΠ°Ρ Ρ‚Π΅ΠΎΡ€ΠΈΡŽ CSP.

Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΏΡ€ΠΎΡΡ‚ΠΈΡ‚ΡŒ написаниС CSP, Π² CSP3 вводится Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Π° strict-dynamic. ВмСсто Ρ‚ΠΎΠ³ΠΎ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ большой Π±Π΅Π»Ρ‹ΠΉ список Π½Π°Π΄Π΅ΠΆΠ½Ρ‹Ρ… источников, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ случайноС число (nonce) ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅Ρ‚ΡΡ страница. Π­Ρ‚ΠΎΡ‚ nonce отправляСтся вмСстС с Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°ΠΌΠΈ страницы ΠΈ встроСн Π² Ρ‚Π΅Π³ script, Ρ‡Ρ‚ΠΎ заставляСт Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π΄ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ этим скриптам с ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ nonce, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π»ΡŽΠ±Ρ‹ΠΌ скриптам, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΎΠ½ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ. ВмСсто Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Π½ΠΎΡΠΈΡ‚ΡŒ скрипты Π² Π±Π΅Π»Ρ‹ΠΉ список ΠΈ ΠΏΡ‹Ρ‚Π°Ρ‚ΡŒΡΡ Π²Ρ‹ΡΡΠ½ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ Π΅Ρ‰Π΅ сцСнарии ΠΎΠ½ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΠΎΠΏΠΎΠ»Π½ΡΡ‚ΡŒ Π±Π΅Π»Ρ‹ΠΉ список рСкурсивно, Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ достаточно внСсти Π² Π±Π΅Π»Ρ‹ΠΉ список ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ скрипт Π²Π΅Ρ€Ρ…Π½Π΅Π³ΠΎ уровня.

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ΠΏΡ€Π΅Π΄Π»ΠΎΠΆΠ΅Π½Π½Ρ‹ΠΉ Google ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Strict CSP, рассмотрим простоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‰Π΅Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π²ΠΎΠ΄. Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ Π΅Π³ΠΎ Π² Ρ„Π°ΠΉΠ»Π΅ xss6.go, Π° Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ go run xss6.go.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 12: ΠŸΡ€ΠΈΠΌΠ΅Ρ€ CSP, ΡΠΌΡΠ³Ρ‡Π°ΡŽΡ‰Π΅Π³ΠΎ XSS-Π°Ρ‚Π°ΠΊΡƒ.
package main

import (
	"bytes"
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"strings"
)

const scriptContent = `
document.addEventListener('DOMContentLoaded', function () {
   var updateButton = document.getElementById("textUpdate");
   updateButton.addEventListener("click", function() {
      var p = document.getElementById("content");
      var message = document.getElementById("textInput").value;
      p.innerHTML = message;
   });
};
`

const htmlContent = `
<html>
   <head>
      <script src="script.js" nonce="{{ . }}"></script>
   </head>
   <body>
       <p id="content"></p>

       <div class="input-group mb-3">
         <input type="text" class="form-control" id="textInput">
         <div class="input-group-append">
           <button class="btn btn-outline-secondary" type="button" id="textUpdate">Update</button>
         </div>
       </div>

       <blockquote class="twitter-tweet" data-lang="en">
         <a href="https://twitter.com/jack/status/20?ref_src=twsrc%5Etfw">March 21, 2006</a>
       </blockquote>
       <script async src="https://platform.twitter.com/widgets.js"
         nonce="{{ . }}" charset="utf-8"></script>
   </body>
</html>
`

func generateNonce() (string, error) {
	buf := make([]byte, 16)
	_, err := rand.Read(buf)
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(buf), nil
}

func generateHTML(nonce string) (string, error) {
	var buf bytes.Buffer

	t, err := template.New("htmlContent").Parse(htmlContent)
	if err != nil {
		return "", err
	}

	err = t.Execute(&buf, nonce)
	if err != nil {
		return "", err
	}

	return buf.String(), nil
}

func generatePolicy(nonce string) string {
	s := fmt.Sprintf(`'nonce-%v`, nonce) 
	var contentSecurityPolicy = []string{
		`object-src 'none';`,
		fmt.Sprintf(`script-src %v 'strict-dynamic';`, s),
		`base-uri 'none';`,
	}
	return strings.Join(contentSecurityPolicy, " ")
}

func scriptHandler(w http.ResponseWriter, r *http.Request) {
	nonce, err := generateNonce()
	if err != nil {
		returnError()
		return
	}

	w.Header().Set("X-XSS-Protection", "0")
	w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
	w.Header().Set("Content-Security-Policy", generatePolicy(nonce))

	fmt.Fprintf(w, scriptContent)
}

func htmlHandler(w http.ResponseWriter, r *http.Request) {
	nonce, err := generateNonce()
	if err != nil {
		returnError()
		return
	}

	w.Header().Set("X-XSS-Protection", "0")
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.Header().Set("Content-Security-Policy", generatePolicy(nonce))

	htmlContent, err := generateHTML(nonce)
	if err != nil {
returnError()
		return
	}

	fmt.Fprintf(w, htmlContent)
}

func returnError() {
http.Error(w, http.StatusText(http.StatusInternalServerError),
		http.StatusInternalServerError)
}

func main() {
	http.HandleFunc("/script.js", scriptHandler)
	http.HandleFunc("/", htmlHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΏΡ‹Ρ‚Π°Ρ‚ΡŒΡΡ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС: http://localhost:8080 ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ <img src=1 onerror"alert(1)"/> ΠΊΠ°ΠΊ ΠΈ Ρ€Π°Π½ΡŒΡˆΠ΅. Π­Ρ‚Π° Π°Ρ‚Π°ΠΊΠ° сработала Π±Ρ‹ ΠΈ Π±Π΅Π· CSP, Π½ΠΎ ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ CSP Π½Π΅ допускаСт inline-скриптов, Π²Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊΠΎΠΉ Π²Ρ‹Π²ΠΎΠ΄ Π² консоли Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π°:

Β«ΠžΡ‚ΠΊΠ°Π·Π°Π½ΠΎ Π² Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ встроСнного ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° событий, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ½ Π½Π°Ρ€ΡƒΡˆΠ°Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρƒ CSP: "script-src 'nonce-XauzABRw9QtE0bzoiRmslQ==' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:" ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ 'unsafe-inline' игнорируСтся, Ссли Π² исходном спискС присутствуСт Π»ΠΈΠ±ΠΎ Ρ…ΡΡˆ, Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ nonce.Β»

ΠŸΠΎΡ‡Π΅ΠΌΡƒ сцСнарий Π½Π΅ запустился? Рассмотрим CSP ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅.

Π€Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚ 13: Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ CSP. Nonce ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ гСнСрируСтся для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ запроса.
script-src 'strict-dynamic' 'nonce-XauzABRw9QtE0bzoiRmslQ==';
object-src 'none';
base-uri 'none';
Π§Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ эта ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ°? Π”ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Π° script-src Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ strict-dynamic ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ nonce, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ΅ для Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ скриптов. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ СдинствСнныС скрипты, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹, находятся Π² script elements, Π³Π΄Π΅ nonce Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ Π² Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚, Π° Π·Π½Π°Ρ‡ΠΈΡ‚ inline-скрипты Π½Π΅ загрузятся. ПослСдниС Π΄Π²Π΅ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΈΠ²Ρ‹ ΠΏΡ€Π΅ΠΏΡΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² ΠΈ измСнСнию Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ URL прилоТСния.

Основная ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ использования этого ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π° Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² нСобходимости Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ nonce ΠΈ ΠΈΠ½ΠΆΠ΅ΠΊΡ‚ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ страницы. ПослС этого шаблон ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ ΠΊΠΎ всСм Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹ΠΌ страницам.

Π‘ΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ устранСния

Content-Type

Π’Ρ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ свой Content-Type, Π½ΠΎ ΠΈ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π½Π΅ ΠΏΡ‹Ρ‚Π°Π»ΠΈΡΡŒ автоматичСски ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π°. Для этого ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ: X-Content-Type-Options: nosniff.

Virtual doms

Π₯отя Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Π΅ Π΄ΠΎΠΌΠ΅Π½Ρ‹ Π½Π΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ бСзопасности, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ ΠΈΡ… соврСмСнныС Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ (React ΠΈ Vue) ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠΌΠΎΡ‡ΡŒ ΡΠΌΡΠ³Ρ‡ΠΈΡ‚ΡŒ Π°Ρ‚Π°ΠΊΠΈ XSS Π½Π° основС DOM.

Π­Ρ‚ΠΈ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ DOM ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ с Ρ‚Π΅ΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ находится Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅, ΠΈ ΡΡ€Π°Π²Π½ΠΈΠ²Π°ΡŽΡ‚ ΠΈΡ…. ΠžΡ‚Π»ΠΈΡ‡Π°ΡŽΡ‰ΡƒΡŽΡΡ Ρ‡Π°ΡΡ‚ΡŒ DOM Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° ΠΎΠ½ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡŽΡ‚. Для этого Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΉ DOM, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡŽ использования ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°ΠΌΠΈ innerHTML ΠΈ ΠΏΠΎΠ΄Ρ‚ΠΎΠ»ΠΊΠ½Π΅Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² ΠΊ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Ρƒ Π½Π° innerText.

React Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ использования Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π° dangerouslySetInnerHTML, Π² Ρ‚ΠΎ врСмя ΠΊΠ°ΠΊ создатСли Vue ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π°ΡŽΡ‚, Ρ‡Ρ‚ΠΎ использованиС innerHTML ΠΌΠΎΠΆΠ΅Ρ‚ привСсти ΠΊ появлСнию уязвимостСй.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Если Π²Ρ‹ Π΄ΠΎΡ‡ΠΈΡ‚Π°Π»ΠΈ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π°, Ρƒ вас ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡΠ²ΠΈΡ‚ΡŒΡΡ ΠΆΠ΅Π»Π°Π½ΠΈΠ΅ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒΡΡ, ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ошибки XSS ΠΈ насколько Π²Π°ΠΆΠ½ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΎΡ‚ Π½ΠΈΡ… ΠΈΠ·Π±Π°Π²ΠΈΡ‚ΡŒΡΡ. XSS Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ ΠΈΡΠΊΠΎΡ€Π΅Π½ΠΈΡ‚ΡŒ, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ прилоТСния становятся всС большС ΠΈ всС слоТнСС. ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΡ упомянутыС Π² ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Тизнь Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊΠΎΠ² Ρ‚Ρ€ΡƒΠ΄Π½ΠΎΠΉ.

Π£Π΄Π°Ρ‡ΠΈ Π² Π±ΠΎΡ€ΡŒΠ±Π΅ ΠΈ ΡƒΡ‡Π΅Π±Π΅!

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹:

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
12 фСвраля 2018

Π›ΡƒΡ‡ΡˆΠΈΠΉ хакСрский курс с Kali Linux Π½Π° русском языкС

Если Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ сСрвСру, ΠΏΠΎΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚ΠΎΡΠΏΠΎΡΠΎΠ±Π½ΠΎΡΡ‚ΡŒ Ρ‡ΡƒΠΆΠΎΠΉ сСт...
Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° программиста
15 января 2018

Как ΡΡ‚Π°Ρ‚ΡŒ Ρ…Π°ΠΊΠ΅Ρ€ΠΎΠΌ: Π³Π°ΠΉΠ΄ ΠΏΠΎ основам для Π½ΠΎΠ²ΠΈΡ‡ΠΊΠΎΠ²

Π₯акСрство - это поиск уязвимостСй Π² сСти ΠΈΠ»ΠΈ ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€Π΅ с Ρ†Π΅Π»ΡŒΡŽ получСния Π΄...
admin
11 фСвраля 2017

5 способов Π²Π·Π»ΠΎΠΌΠ° страницы Π’ΠšΠΎΠ½Ρ‚Π°ΠΊΡ‚Π΅

Π’ нашС врСмя ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒ доступ ΠΊ Π»ΠΈΡ‡Π½Ρ‹ΠΌ Π΄Π°Π½Π½Ρ‹ΠΌ, Ссли Π½Π΅ ΠΏΡ€ΠΈΠ΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒΡΡ ...