浏览器保护API请求:在前端和后端之间建立安全的通信


, (SPA), . , , - API-, — . , , .


HTML-JS «» . — , .


— - FirstVDS. SPA , API . , .


?


- . , (SQL-, , DDoS ). , , . : XSS CSRF (XSRF), .


XSS — . , , . JS, HTML CSS . — . . , XSS- . , email, . , , , , . XSS- .


CSRF (XSRF) — . cookie . , , 10000000 , , . POST- , , — . cookies — . , CSRF-.


, . - OWASP.


, . , - . API-, -, . .


CORS


XHR-. . HTML- (, , ), Same Origin Policy. , .


, , : Nginx -, URI. , .


server {
    listen 443;
    server_name service.test;
    location /api {
        proxy_pass http://backend.test;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location / {
        proxy_pass http://frontend.test;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

. , API , , - , API, . XHR- Cross-Origin Resource Sharing, CORS. , — . , CORS. , «-» , — , . , XHR- , cookie (CSRF-).


, CORS, -. Nginx:


server {
    listen 443;
    server_name api.service.test;
    location / {
        proxy_pass api;
        add_header 'Access-Control-Allow-Origin' 'https://service.test';
    }
}

Access-Control-Allow-Origin , . : OPTIONS , , Access-Control-Allow-Origin . ‘*’, «». XHR- . , API, . , . , , Access-Control-Allow-Origin .


, CORS- — . API , , -. , : Access-Control-Allow-Origin , API .


-


Access-Control-Allow-Origin, . - , , HTML- , . -, , .


X-Frame-Options


, iFrame. , iFrame .


    location / {
        add_header X-Frame-Options deny;
    }

Clickjacking. iFrame, . X-Frame-Options Content Security Policy, .


X-Content-Type-Options


, MIME Sniffing. , . HTML- MIME- MIME-, text/html. XSS-. , CORS, . X-Content-Type-Options ‘nosniff’ MIME-. — - , .


    location /upload {
        add_header X-Content-Type-Options nosniff;
    }

Strict-Transport-Security


- , HSTS, https. , , , , Wi-Fi, . — 1 .


    location / {
        add_header Strict-Transport-Security "max-age=31536000";
    }

Content Security Policy


, , — Content Security Policy. , , x-xss-protection x-frame-options. «» , -. : , JS-, CSS, , XHR- . , XHR- , ..


CSP -:


    location / {
        proxy_pass api;
        set $CSP "default-src 'self';";
        set $CSP "${CSP} img-src 'self' https://mc.yandex.ru https://www.google-analytics.com;";
        set $CSP "${CSP} frame-ancestors 'self';";
        set $CSP "${CSP} style-src 'self';";
        set $CSP "${CSP} font-src 'self';";
        set $CSP "${CSP} connect-src https://api.service.test *.google-analytics.com https://mc.yandex.ru;";
        add_header Content-Security-Policy $CSP;
    }

: -, , API.


- HTML-:


  <meta http-equiv="Content-Security-Policy" content="
    default-src 'self';
    connect-src https://service.test *.google-analytics.com https://mc.yandex.ru;
    script-src 'self' *.google-analytics.com *.googletagmanager.com https://mc.yandex.ru;
    img-src 'self' https://mc.yandex.ru https://www.google-analytics.com;
    frame-ancestors 'self';
    style-src 'self';
    font-src 'self'; ">

, CSP inline- . XSS , .



, . , . . -.


4 , :


  • Cookie
  • localStorage
  • Session storage
  • HttpOnly Cookie

IndexedDB — , , , . .


— -, - — API, . , , , - () , . ?



. JS , Set-Cookie. Cookies , Same Origin Policy, . — credentials. Cookies CSRF-. samesite, , . , Cookie XSS . (4) cookies .


localStorage


localStorage ( --), , -. . , , localStorage, , , , localStorage CSRF. — , Cookie. , localStorage XSS-, .


Session storage


localStorage, , . , . , websocket-. — .


HttpOnly ookie


Cookies, : - Cookies httpOnly. , Cookies . cookie set-cookie . XSS-. CSRF, .


, .


XSS


XSS- , -, JS, HTML CSS. , -, , -, , , . CSP, . , . . -:


1) 100% . npm audit (yarn audit). CI/CD, npm audit --audit-level=moderate . npm audit moderate , . , , . .


2) «» , . «» . :


& --> &amp;
 < --> &lt;
 > --> &gt;
 " --> &quot;
 ' --> &#x27;     
 / --> &#x2F; 

- , . , Vue mustache ({{value}}), v-html. , HTML . , . , , . , , HtmlSanitizer.


3) JS eval(). , .


4) ookie. — - HttpOnly ookie.


5) . , - CMS, service.test. , path, service.test/account, localStorage. CMS XSS, localStorage .


6) OWASP.


CSRF


— . , «-». , .


, . , , . , : 10 — . 2 : (access_token) (refresh_token). access_token API, refresh_token API access_token. ? refresh_token access_token. , , REST API.


POST /auth :


Body{"username": "vasya","password": "vasya_hard_password"}{"access_token": "long_access_token"}

, access_token. - xhr-, GET /user


Body{"username": "vasya","password": "vasya_hard_password"}{"access_token": "long_access_token"}
HeadersAuthorization: Baerer long_access_token

access_token, , 10 , , 10 . « », refresh_token, , , . , , , . 2 : localStorage, , httpOnly Cookie, . Session storage , , Cookie .
, refresh token -, , API , access_token .


, API, Cookie . access_token . access_token . localStorage access_token — XSS. refresh_token httpOnly cookie. , POST /token/auth Set-cookie.


Body{"username": "vasya","password": "vasya_hard_password"}{"access_token": "long_access_token"}
HeadersSet-cookie: refresh_token=long_refresh_token; Domain=api.service.test; Expires=Date; HttpOnly; Secure;

, cookies CSRF-. refresh_token CSRF CSRF-. ? ? ? , access_token. , POST /refresh .


POST /token/refresh 2 : access_token localStorage refresh_token httpOnly cookie cookie


Body{"access_token": "long_access_token"}
HeadersX-CSRF-Token: long_access_token; cookie: refresh_token=long_refresh_token

access_token X-CSRF-Token , , (~ refresh_token).
, CORS, XHR- cookie withCredentials: true XMLHttpRequest credentials: 'include' fetch. cookie, httpOnly, , .


, access_token refresh_token , XSS CSRF-, .


API


API . , - . , ? Access-Control-Allow-Origin . . -, . -, ookie credentials, Access-Control-Allow-Origin , .


, Nginx, . . ookie , . , cookie , .


— API Nginx :


upstream api {
    server unix:/opt/api/server.sock;
}

server {
    listen 443;
    server_name api1.service.test;
    location / {
        proxy_pass api;
        add_header 'Access-Control-Allow-Origin' 'https://frontend1.service.test';
    }
}

server {
    listen 443;
    server_name api2.service.test;
    location / {
        proxy_pass api;
        add_header 'Access-Control-Allow-Origin' 'https://frontend2.service.test';
    }
}

C - CSP :


server {
    listen 443;
    server_name frontend1.service.test;
    root "/var/www/frontend";
    index index.html;
    location / {
        set $CSP "default-src 'self';";
        set $CSP "...";
        set $CSP "${CSP} connect-src https://api1.service.test ...";
        add_header Content-Security-Policy $CSP;
    }
}

server {
    listen 443;
    server_name frontend2.service.test;
    root "/var/www/frontend";
    index index.html;
    location / {
        set $CSP "default-src 'self';";
        set $CSP "...";
        set $CSP "${CSP} connect-src https://api2.service.test ...";
        add_header Content-Security-Policy $CSP;
    }
}


, , — -. - , . , , «» , .


: « 100%-. — , , ».


All Articles