TL; DR:為長篇文章道歉。簡而言之,我正在嘗試除錯 CSP report-uri。如果我遺漏了關鍵資訊,請告訴我。
CSP實作:Flask-Talisman
需要設定的屬性:content_security_policy_report_uri
似乎沒有很多關于如何捕獲此報告的資訊
我在Flask-Talisman檔案中找不到任何具體內容
由于Flask-Talisman只設定標題,包括report-uri,我想這無論如何都超出了擴展的范圍
路線
我發現的所有資源都具有大致相同的功能:
https
: //www.merixstudio.com/blog/content-security-policy-flask-and-django-part-2/ http://csplite.com/csp260/
https://github.com/GoogleCloudPlatform/flask-talisman/issues/21
我為這條路線找到的唯一真正詳細的解釋如下(但與此無關Flask-Talisman)
來自https://www.merixstudio.com/blog/content-security-policy-flask-and-django-part-2/(這是我目前使用的)
# app/routes/report.py
import json
import pprint
from flask import request, make_response, Blueprint
...
bp = Blueprint("report", __name__, url_prefix="report")
...
@bp.route('/csp-violations', methods=['POST'])
def report():
"""Receive a post request containing csp-resport.
This is the report-uri. Print report to console and
return Response object.
:return: Flask Response object.
"""
pprint.pprint(json.loads(str(request.data, 'utf-8')))
response = make_response()
response.status_code = 200
return response
...
這條路線只收到 400 錯誤,我不知道如何實際除錯它
127.0.0.1 - - [04/Nov/2021 14:29:09] "POST /report/csp-violations HTTP/1.1" 400 -
我嘗試過 GET 請求,可以看到我收到了一個空請求,這似乎意味著沒有發送 CSP 報告(來自 的回應https://127.0.0.1:5000/report/csp-violations)
# app/routes/report.py
...
@bp.route('/csp-violations', methods=['GET', 'POST'])
def report():
...
b''
b''
127.0.0.1 - - [04/Nov/2021 18:03:52] "GET /report/csp_violations HTTP/1.1" 200 -
Edit: Definitely receiving nothing
...
@bp.route("/csp_violations", methods=["GET", "POST"])
def report():
...
return str(request.args) # ImmutableMultiDict([ ])
Will not work with a GET or POST request (still 400)
...
@bp.route("/csp_violations", methods=["GET", "POST"])
def report():
content = request.get_json(force=True)
...
Without force=True
@bp.route("/csp_violations", methods=["GET", "POST"])
def report():
content = request.get_json() # json.decoder.JSONDecodeError
...
Chromium (same result on Chrome, Brave, and FireFox)
When I check this out on Chromium under CTRL-SHIFT-I > Network I see
Request URL: https://127.0.0.1:5000/report/csp_violations
Request Method: POST
Status Code: 400 BAD REQUEST
Remote Address: 127.0.0.1:5000
Referrer Policy: strict-origin-when-cross-origin
But apparently the payload does exist at the bottom under "Request Payload"...
{
"document-uri": "https://127.0.0.1:5000/",
"referrer": "",
"violated-directive": "script-src-elem",
"effective-directive": "script-src-elem",
"original-policy": "default-src 'self' https://cdnjs.cloudflare.com https://cdn.cloudflare.com https://cdn.jsdelivr.net https://gravatar.com jquery.js; report-uri /report/csp-violations",
"disposition": "enforce",
"blocked-uri": "inline",
"line-number": 319,
"source-file": "https://127.0.0.1:5000/",
"status-code": 200,
"script-sample": ""
}
Is the CSP blocking this request?
After reading Python Flask 400 Bad Request Error Every Request I set all requests to HTTPS with the help of https://stackoverflow.com/a/63708394/13316671
This fixed a few unittests but no change to the 400 error for this particular route
# app/config.py
from environs import Env
from flask import Flask
env = Env()
env.read_env()
class Config:
"""Load environment."""
...
@property
def PREFERRED_URL_SCHEME(self) -> str: # noqa
return env.str("PREFERRED_URL_SCHEME", default="https")
...
# app/__init__.py
from app.config import Config
def create_app() -> Flask:
app = Flask(__name__)
app.config.from_object(Config())
...
return app
flask run --cert="$HOME/.openssl/cert.pem" --key="$HOME/.openssl/key.pem"
400 Bad Request
Through what I've read a 400 Bad Request error usually happens from an empty request or form
https://stackoverflow.com/a/14113958/13316671
...the issue is that Flask raises an HTTP error when it fails to find a key in
the args and form dictionaries. What Flask assumes by default is that if you
are asking for a particular key and it's not there then something got
left out of the request and the entire request is invalid.
https://stackoverflow.com/a/37017020/13316671
99% of the time, this error is a key error caused by your requesting a key in
the request.form dictionary that does not exist. To debug it, run
print(request.form)
request.data in my case
Through trying to fix this I have gone down the rabbit-hole in regard to just seeing the cause of the 400 error
I have implemented the following
https://stackoverflow.com/a/34172382/13316671
import traceback
from flask import Flask
...
app = Flask(__name__)
...
@app.errorhandler(400)
def internal_error(exception): # noqa
print("400 error caught")
print(traceback.format_exc())
And added the following to my config
I haven't checked, but I think these values already get set alongside DEBUG
# app/config.py
from environs import Env
env = Env()
env.read_env()
class Config:
"""Load environment."""
...
@property
def TRAP_HTTP_EXCEPTIONS(self) -> bool: # noqa
"""Report traceback on error."""
return env.bool("TRAP_HTTP_EXCEPTIONS", default=self.DEBUG) # noqa
@property
def TRAP_BAD_REQUEST_ERRORS(self) -> bool: # noqa
"""Report 400 traceback on error."""
return env.bool("TRAP_BAD_REQUEST_ERRORS", default=self.DEBUG) # noqa
...
I still am not getting a traceback. The only time werkzeug shows a traceback is through a complete crash, for something like a syntax error
It seems, because I am not initializing this request that the app continues to run through the 400 code, no problem
Summary
Main conclusion I'm drawing is that for some reason the report-uri is not valid because I can see the payload exists, I am just not receiving it
I used the relative route as the subdomain would be different for a localhost and a remote. It looks as though the request is being made to the full URL in the Chromium snippet though.
Could I be receiving invalid headers https://stackoverflow.com/a/45682197? If so how can I debug that?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/report-uri
Note: The report-uri is deprecated, but I don't think most browsers support the report-to parameter
EDIT:
I have taken the following out of my application factory (this code renders my exceptions - which I posted as an answer here so it is available https://stackoverflow.com/a/69671506/13316671
...
app = Flask(__name__)
config.init_app(app)
...
# exceptions.init_app(app)
...
return app
執行此操作后(在 FireFox 私有模式下),我進行了另一個 POST(我已經洗掉了 GET 方法)我可以看到回應 - 在這里我終于設法收集了 Werkzeug 回溯:
wtforms.validators.ValidationError: The CSRF token is missing.
研究如何驗證來自瀏覽器的 csp 報告
到目前為止,我已經看過這個:在 Content-Security-Policy-Report-Only "report-uri" POST call 中添加一個新的 Http Header
uj5u.com熱心網友回復:
試試這段代碼:
@app.route('/report-csp-violations', methods=['POST'])
def report():
content = request.get_json(force=True) # that's where the shoe pinches
print(json.dumps(content, indent=4, sort_keys=True))
response = make_response()
response.status_code = 204
return response
我認為request.data嘗試自動決議 JSON 資料并成功決議它期望application/json發送 MIME 型別。
但是違規報告是使用application/csp-reportMIME 型別發送的,因此 Flask 將其視為來自客戶端的錯誤資料 -> 404 Bad Request。
.get_json(force=True) 意味著忽略 mimetype 并始終嘗試決議 JSON。
此外,我認為您不需要轉換為 utf-8,因為根據rfc4627 “3. 編碼”:
JSON 文本應以 Unicode 編碼。默認編碼為 UTF-8。
uj5u.com熱心網友回復:
現在,我已將視圖從CRSFProtect. 我認為應該沒問題,因為此視圖不回傳模板,所以我無法添加
<form method="post">
{{ form.csrf_token }}
</form>
以下對我不起作用(不要認為這是一個有效的令牌)
# app/routes/report.py
...
def report():
response = make_response()
response.headers["X-CSRFToken"] = csrf.generate_csrf()
...
return response
...
使用實體化CSRFProtect物件...
# app/extensions.py
...
from flask_wtf.csrf import CSRFProtect
...
csrf_protect = CSRFProtect()
...
def init_app(app: Flask) -> None:
...
csrf_protect.init_app(app)
...
...
...裝飾視圖
# app/routes/report.py
from app.extensions import csrf_protect
...
@blueprint.route("/csp_violations", methods=["POST"])
@csrf_protect.exempt
def report():
....
127.0.0.1 - - [06/Nov/2021 21:30:46] "POST /report/csp_violations HTTP/1.1" 204 -
{
"csp-report": {
"blocked-uri": "inline",
"column-number": 8118,
"document-uri": "https://127.0.0.1:5000/",
"line-number": 3,
"original-policy": "default-src" ...
"referrer": "",
"source-file": ...
}
}
我有一個系統可以混淆我的錯誤,所以這是我的錯誤。這不是我第一次遇到CSRFProtect.
我已經解決了除錯問題
# app/exceptions.py
...
def init_app(app: Flask) -> None:
...
def render_error(error: HTTPException) -> Tuple[str, int]:
# the below code is new
app.logger.error(error.description)
...
...
所以,如果我仍然收到此錯誤,這就是我現在會看到的
[2021-11-06 21:23:56,054] ERROR in exceptions: The CSRF token is missing.
127.0.0.1 - - [06/Nov/2021 21:23:56] "POST /report/csp_violations HTTP/1.1" 400 -
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/350566.html
下一篇:具有測量引導的TPM芯片的安全性
