Skip to main content

V1.12.2 Secure File Upload Architecture

Requirement:#

Verify that user-uploaded files - if required to be displayed or downloaded from the application - are served by either octet stream downloads, or from an unrelated domain, such as a cloud file storage bucket. Implement a suitable Content Security Policy (CSP) to reduce the risk from XSS vectors or other attacks from the uploaded file.

Explanation:#

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

  • User-Uploaded Files: Π­Ρ‚ΠΎ Π»ΡŽΠ±Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΠΌΠΎΠ³ΡƒΡ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, изобраТСния, Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ‹, Π²ΠΈΠ΄Π΅ΠΎ ΠΈ Ρ‚.Π΄.
  • Octet Stream Downloads: ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Ρ„Π°ΠΉΠ»ΠΎΠ² Π² Π²ΠΈΠ΄Π΅ "Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΎΠΊΡ‚Π΅Ρ‚Π½ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°" ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΡƒ Ρ„Π°ΠΉΠ»ΠΎΠ² с Ρ‚ΠΈΠΏΠΎΠΌ содСрТимого "application/octet-stream", Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½Ρ‹ Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°Ρ‚ΡŒ ΠΈΡ… ΠΊΠ°ΠΊ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅, Π° Π½Π΅ Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΡ‚ΡŒ ΠΈΡ… Π² самом Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅.
  • Unrelated Domain (Cloud Storage): ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ Π΄ΠΎΠΌΠ΅Π½Π°, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ ΠΈΠ· ΠΎΠ±Π»Π°Ρ‡Π½ΠΎΠ³ΠΎ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π°, позволяСт ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ ΠΎΡ‚ основного Π΄ΠΎΠΌΠ΅Π½Π° прилоТСния.
  • Content Security Policy (CSP): CSP - это функция бСзопасности, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰Π°Ρ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠΌ источникам ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΈΠ»ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π²Π΅Π±-страницу.

Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ Ρ„Π°ΠΉΠ»Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ для осущСствлСния Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… Π°Ρ‚Π°ΠΊ, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ Cross-Site Scripting (XSS), распространСниС врСдоносного ПО ΠΈ ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠ΅ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π°. Π”Π°Π½Π½ΠΎΠ΅ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π½Π° ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ Ρ‚Π°ΠΊΠΈΡ… Π°Ρ‚Π°ΠΊ ΠΏΡƒΡ‚Π΅ΠΌ обСспСчСния Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π½Π΅ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»ΠΈΡΡŒ Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… контСкста прилоТСния, Π° Ρ‚Π°ΠΊΠΆΠ΅ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»ΠΈΡΡŒ ΠΈΠ· бСзопасных ΠΈ ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… источников.

Remediation:#

Π§Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ это Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρ‹ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ² Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ дСйствия:

1 Octet Stream Downloads: НастройтС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ Ρ„Π°ΠΉΠ»Ρ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π»ΠΈΡΡŒ Π² Π²ΠΈΠ΄Π΅ ΠΎΠΊΡ‚Π΅Ρ‚-ΠΏΠΎΡ‚ΠΎΠΊΠ°, Π° Π½Π΅ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π»ΠΈΡΡŒ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅.

2 Unrelated Domain (Cloud Storage): Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Π΅ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° Ρ„Π°ΠΉΠ»ΠΎΠ² (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Amazon S3, Google Cloud Storage) для хранСния ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Ρ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΌ Ρ„Π°ΠΉΠ»ΠΎΠ².Β Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ подписанныС URL-адрСса ΠΈΠ»ΠΈ срСдства контроля доступа, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ доступ ΠΊ Ρ„Π°ΠΉΠ»Π°ΠΌ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ.

3 Content Security Policy (CSP): Π’Π½Π΅Π΄Ρ€ΠΈΡ‚Π΅ CSP Π² header HTTP-response прилоТСния. НастройтС CSP Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°ΠΏΡ€Π΅Ρ‚ΠΈΡ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ скриптов ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΡ‚ΡŒ использованиС ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π° ΠΈΠ· бСзопасных источников.

4 Whitelisting MIME Types: ВнСситС Π² Π±Π΅Π»Ρ‹ΠΉ список ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ MIME, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ бСзопасны для отобраТСния ΠΈΠ»ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ. ΠžΡ‚ΠΊΠ»ΠΎΠ½ΡΠΉΡ‚Π΅ Π»ΡŽΠ±Ρ‹Π΅ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, содСрТащиС Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½Π½Ρ‹Π΅ ΠΈΠ»ΠΈ нСбСзопасныС Ρ‚ΠΈΠΏΡ‹ MIME.

К ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρƒ, Π² Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅Ρ‚ Ρ„ΠΎΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΡŽ профиля, ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΌΠ΅Ρ€Ρ‹ для выполнСния Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π½ΠΈΠΉ:

  • Π—Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ ΠΏΠΎΠ΄Π²Π΅Ρ€Π³Π°ΡŽΡ‚ΡΡ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅ ΠΈ очисткС для прСдотвращСния Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ³ΠΎ врСдоносного ΠΊΠΎΠ΄Π°.
  • ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Π΅ изобраТСния профиля Π² Π²ΠΈΠ΄Π΅ ΠΎΠΊΡ‚Π΅Ρ‚Π½ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°, заставляя Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Ρ‹ Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ ΠΈΡ… ΠΊΠ°ΠΊ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹.
  • Π€ΠΎΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΠΈ профиля Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚ΡΡ с ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ΄Π΄ΠΎΠΌΠ΅Π½Π°, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ cdn.example.com, Π½Π΅ связанного с основным Π΄ΠΎΠΌΠ΅Π½ΠΎΠΌ прилоТСния.Β 
  • Π’ HTML-Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ прилоТСния Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠ° Content Security Policy (CSP). Она Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ скриптов Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ· Π΄ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹Ρ… источников ΠΈ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ вставку скриптов ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ опасного содСрТимого.
ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ бСзопасного Ρ„ΡƒΠ½ΠΈΠΊΡ†ΠΈΠΎΠ½Π°Π»Π° Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ²
from flask import Flask, request, send_file, safe_join
import os
import hashlib
import secrets
from flask_talisman import Talisman
app = Flask(__name__)
Talisman(app)
UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return "No file part"
file = request.files['file']
if file.filename == '':
return "No selected file"
if file and allowed_file(file.filename):
filename = secrets.token_hex(16) + "." + file.filename.rsplit('.', 1)[1].lower()
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
return "File uploaded successfully"
else:
return "File type not allowed"
@app.route('/download/<filename>', methods=['GET'])
def download_file(filename):
filepath = safe_join(app.config['UPLOAD_FOLDER'], filename)
if os.path.exists(filepath):
return send_file(filepath, as_attachment

Π’ Π΄Π°Π½Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅:

  • Для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠΎΠ»ΠΈΡ‚ΠΈΠΊΠΈ Content Security Policy (CSP) ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Flask-Talisman.
  • ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ UPLOAD_FOLDER Π·Π°Π΄Π°Π΅Ρ‚ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π±ΡƒΠ΄ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹.
  • Ѐункция allowed_file провСряСт, ΠΈΠΌΠ΅Π΅Ρ‚ Π»ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ°Π΅ΠΌΡ‹ΠΉ Ρ„Π°ΠΉΠ» Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½Π½ΠΎΠ΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅.
  • ΠŸΡƒΡ‚ΡŒ /upload бСзопасно ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ Ρ„Π°ΠΉΠ»ΠΎΠ². Π€Π°ΠΉΠ»Ρ‹ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ΡΡ с ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΈΠΌΠ΅Π½Π°ΠΌΠΈ.
  • ΠŸΡƒΡ‚ΡŒ /download/filename позволяСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌ бСзопасно Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π² Π²ΠΈΠ΄Π΅ ΠΎΠΊΡ‚Π΅Ρ‚Π½ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°.

Additional:#

https://developer.mozilla.org/ru/docs/Web/HTTP/CSP)%20%D0%B8%20%D0%B0%D1%82%D0%B0%D0%BA%D0%B8%20%D0%B2%D0%BD%D0%B5%D0%B4%D1%80%D0%B5%D0%BD%D0%B8%D1%8F%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85).