定义
CSP是一种由浏览器实施的安全机制,其核心目的是减少和防范跨站脚本攻击(XSS)等安全威胁。它通过允许网站管理员定义哪些内容来源是可信任的,从而防止恶意内容的加载和执行。CSP通过HTTP响应头中的Content-Security-Policy字段实现,其核心理念是通过白名单机制来严格限制网页中资源的加载和执行
作用
1、限制资源获取:明确指定哪些外部资源(如脚本、样式表、图片等)可以被加载和执行,有效防止恶意资源的注入。
2、报告资源获取越权:在报告模式下,CSP可以记录违反策略的行为,帮助开发者发现并修复潜在的安全问题,而不影响用户的正常访问。
3、增强用户信任:通过实施CSP,网站可以向用户展示其对安全性的重视,增强用户对网站的信任度。
原理
CSP通过HTTP响应头中的Content-Security-Policy字段向浏览器发送一系列指令,这些指令定义了哪些资源是允许加载和执行的。浏览器在加载和执行资源时,会根据这些指令进行严格的验证,只有符合规则的资源才会被加载和执行。
一句话总结就是服务器通过Content-Security-Policy 响应头告诉浏览器哪些可以执行哪些不能执行,用此方法来网页可以加载的资源和页面,防止XSS攻击
default-src:设置默认加载资源的策略(例如,自身的源、任何地方的源、或者不加载任何外部资源)。
script-src:定义哪些脚本可以执行, 例如script标签, a标签的JavaScript:location.href="" 等.
style-src:定义哪些样式表可以加载。
img-src:定义哪些图片资源可以加载。
connect-src:限制可以通过脚本接口进行连接的URL(例如,AJAX 请求、WebSocket)。
font-src:定义哪些字体资源可以加载。
object-src:限制可以加载哪些插件。
media-src:定义哪些媒体资源(音频和视频)可以加载。
frame-src:定义哪些iframe可以加载。
report-uri:定义接收违反CSP策略报告的URL
配置方式
一、web服务配置示例
response.headers[
'Content-Security-Policy'] = "default-src 'self'; script-src 'self' https://trustedscripts.com; object-src 'none'; report-uri "
二、nginx配置示例
server {
add_header Content-Security-Policy "default-src 'self';";
...
}
三、HTML配置示例
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://apis.example.com; img-src 'self' https://images.example.com; style-src 'self' 'unsafe-inline';">
<title>My Secure Page</title>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>
测试
用python起一个web服务,并构造响应去触发CSP规则
from flask import Flask, jsonify, make_response, request
# 创建一个Flask应用实例
app = Flask(__name__)
# 定义根路由处理函数,当用户访问主页时调用
@app.route('/')
def index():
# 创建HTML响应内容,包含一些可能会违反CSP规则的元素
response = make_response("""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSP Test</title>
</head>
<body>
<h1>Hello, World!</h1>
<!-- 这些标签应该被阻止 -->
<script src="https://pss.bdstatic.com/static/superman/js/components/tips-e2ceadd14d.js"></script> <!-- 尝试加载来自不受信任来源的脚本 -->
<script>alert('This is csp test');</script> <!-- 内联JavaScript,通常会被阻止 -->
<object data="movie.swf" type="application/x-shockwave-flash"></object> <!-- 尝试加载<object>标签,应该被阻止 -->
<embed src="movie.swf" type="application/x-shockwave-flash"></embed> <!-- 尝试加载<embed>标签,应该被阻止 -->
</body>
</html>
""")
# 设置CSP响应头,定义了哪些资源可以加载
# default-src 'self':默认情况下,所有资源只能从当前域加载。
# script-src 'self':允许从当前域和指定的可信域名加载脚本。
# object-src 'none':禁止加载<object>, <embed>, 和 <applet>标签。
# report-uri /csp-report-endpoint:当发生CSP违规时,向这个URL发送报告。
response.headers[
'Content-Security-Policy'] = "default-src 'self'; script-src 'self' 'unsafe-inline' ; object-src 'none'; report-uri "
# 返回构建好的HTTP响应给客户端
return response
# 定义处理CSP违规报告的路由
@app.route('/csp-report-endpoint', methods=['POST'])
def csp_report_endpoint():
# 打印接收到的CSP违规报告到控制台
print("CSP violation reported:", request.json)
# 返回空响应并设置状态码为204 No Content,表示成功接收但无内容返回
return '', 204
# 如果此文件作为主程序运行,则启动Flask应用
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1', port=5005) # 启动应用,在本地主机上监听端口5005,并开启调试模式
CSP规则如下:
Content-Security-Policy: default-src 'self'; script-src 'self' ; object-src 'none'; report-uri
default-src 'self':只允许加载来自同一来源(即当前网站)的资源。
script-src 'self' 'unsafe-inline':只允许执行来自同一来源的脚本,且允许执行内联脚本例如:<script>alert('This should be blocked');</script> 。
object-src 'none':不允许加载任何来源的对象。
report-uri:当页面违反了CSP规则时,浏览器会将违规详情发送到指定的URI,这可以帮助网站管理员监控和调试CSP规则。
下图可以看到服务器的响应,其中因为配置了unsafe-inline,可以执行内联的JS代码,也就是代码里的<script>alert('This should be blocked');</script>,但是因为https://pss.bdstatic.com/static/superman/js/components/tips-e2ceadd14d.js是没有被允许的所以显示被CSP阻断了,我们尝试把上述外联js代码加入到CSP规则的允许范围
可以看到指定的外联js被成功执行了