CSP

1,283 阅读8分钟

CSP

一、CSP概述

概念

内容安全策略(Content Security Policy 简称 CSP)是一种额外的安全层,用于检测和减轻某些类型的攻击,如跨站脚本攻击( XSS )和数据注入攻击等。

CSP通过限制外部资源的来源达到增强网页安全性的问题,实质上就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载,有助于防止恶意脚本执行以及非授权内容的加载,如果网站不提供CSP标头,浏览器也使用标准的同源策略。

通过使用Content-Security-Policy ,网站可以控制用户代理如何执行页面的特定部分,这可以显著减少XSS攻击的风险

img

CSP指令

default-src : 设置默认加载资源的策略(例如,自身的源、任何地方的源、或者不加载任何外部资源)
script-src : 定义哪些脚本可以执行, 例如script标签, a标签的javascript:location.href=""style-src : 定义哪些样式表可以加载。
img-src : 定义哪些图片资源可以加载。
connect-src : 限制可以通过脚本接口进行连接的URL(例如,AJAX请求、WebSocket)
font-src : 定义哪些字体资源可以加载。
object-src : 限制可以加载哪些插件(例如,Flash、based、XSS)
media-src : 定义哪些媒体资源(音频和视频)可以加载
frame-src : 定义哪些iframe可以加载
base-uri : 用于控制base标签能加载的资源范围
child-src : 用于控制子页面加载
form-action:限制form的action
report-uri : 拦截并报告CSP违规
report-sample : 指外界尝试XSS攻击时或有脚本触发了违例,浏览器会异步将payload的前40个字节POST给 report-uri 对应的链接
注意
拦截 Content-Security-Policy 头部
仅是报告而不拦截的CSP Content-Security-Policy-Report-Only 头部

CSP取值

* : 星号表示允许任何URL资源,没有限制
'self' 同源策略,即允许同域名同端口下,同协议下的请求
'unsafe-inline' 允许行内代码执行
'unsafe-eval'   允许不安全的动态代码执行,比如JavaScript的eval()方法
https:  只允许通过https协议加载资源
data:base64  允许通过data来请求咨询 (比如用Base64 编码过的图片)
nonce: 每次HTTP回应给出一个授权token,页面内嵌脚本必须有这个token,才会执行,设置值为:'nonce-12345678'
<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(123)</script>
hash: 列出允许执行的脚本代码的Hash值,页面内嵌脚本的哈希值只有吻合的情况下,才能执行
'sha265-a40fdfd7e1641939698cc595e2568033970a0750a98e85fa7996ea4859ee28be'
<script>alert(123)</script>

CSP开启

后端开启
header("Content-Security-Policy: script-src 'self'"); 
header("Content-Security-Policy: script-src 'self' http://192.168.88.128"); 
header("Content-Security-Policy: script-src 'self' http://192.168.88.128 'unsafe-inline'");
header("Content-Security-Policy: script-src 'self' 'unsafe-inline';img-src 'self';");
前端开启 HTML中配置 <meta>
<meta http-equiv="Content-Security-Policy" content="default-src 'self' http://www.dlrb.com 'unsafe-inline'" >
<meta http-equiv="Content-Security-Policy" content="img-src 'self' http://www.wowo.com">
<meta http-equiv="Content-Security-Policy" content="style-src 'self' 'unsafe-inline'">
<meta http-equiv="Content-Security-Policy" content="child-src 'none';">
注意,使用<meta>标签设置CSP的方法存在一些限制
1. 无法使用某些指令,如frame-ancestors和report-uri
2. 对于由多个页面组成的网站,每个页面都需要包含一个<meta>标签,这可能会导致维护上的困难
3. 与HTTP头设置相比,这种方法可能会更容易遭受某些攻击方式,因为恶意用户可能会尝试注入标签来覆盖你的CSP规则

总的来说,虽然在HTML中设置CSP是可以的,但出于维护和安全性的考虑,通常建议通过HTTP头来设置CSP

CSP全局开启

apache应用服务器的配置文件,路径 /opt/lampp/etc/httpd.conf 配置如下内容

Header set Content-Security-Policy "default-src 'self';"

配置修改需要重启服务器

局部配置可以覆盖全局配置,但是远程的JS文件局部配置无法覆盖,它只能覆盖本地JS的配置

二、CSP实战

所有内容均来自站点的同源 (不包括其子域名)

header("Content-Security-Policy: default-src 'self'");

只允许加载当前域的JS

header("Content-Security-Policy: script-src 'self' 'unsafe-inline'");

这表示只能从当前源和http://192.168.88.166,加载和应用样式

header("Content-Security-Policy: style-src 'self' 'unsafe-inline' http://192.168.88.166");

浏览器只允许加载来自当前源,data: URLs,以及 https://192.168.88.166 的图像

header("Content-Security-Policy: img-src 'self' 'unsafe-inline' data: https://192.168.88.166");

三、CSP报告

拦截并报告CSP违规(常用)

添加 report-uri 指令,

header("Content-Security-Policy: script-src 'self' 'unsafe-inline'; report-uri /wowo/csp-log-edit.php");

在这个例子中,当CSP违规发生时,浏览器会向 csp-log-edit.php 发送json格式的报告。 你需要确保你的服务器端准备好接收和处理这些报告,通常是通过一个PHP脚本来记录这些违规。

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $base = dirname( __FILE__);
    $data = file_get_contents('php://input');
    file_put_contents("$base/log/csp.log", $data, FILE_APPEND);
    header("Content-Type: application/json;charset=utf-8");
    echo json_encode(['success' => true]);
  } else {
    header("HTTP/1.1 405 Method Not Allowed");
    echo "请使用POST请求存储CSP文件";
}

注意这里无法覆盖全局,需要将全局的CSP删除

{"csp-report":{"document-uri":"http://www.dlrb.com/wowo/user.php","referrer":"","violated-directive":"script-src-elem","effective-directive":"script-src-elem","original-policy":"script-src 'self' 'unsafe-inline'; report-uri /wowo/csp-log-edit.php","disposition":"enforce","blocked-uri":"http://www.lyf.com/attack/getcookie.js","status-code":200,"script-sample":""}}

仅报告而不拦截的CSP

可以使用 Content-Security-Policy-Report-Only 头部,而不是 Content-Security-Policy 这个头部的格式与常规的CSP相同,但只用于报告目的。

header("Content-Security-Policy-Report-Only: script-src 'self' 'unsafe-inline'; report-uri /wowo/csp-log-edit.php");

在这种模式下,如果有脚本尝试从其他源加载,这个行为不会被浏览器阻止,但会向指定的URI发送报告。

四、CSP绕过

低级绕过

查看低级的CSP配置

img

没有配置 unsafe-inline ,不允许行内代码执行,只能通过远程网址下手,这几个网址访问不了,我们用 hosts 文件伪造,在攻击服务器创建JS文件,开始进行 XSS 注入

查看注入点

img

绕过
只要在地址栏输入 http://pastebin.com/woniu/js/hook.js 即可

中级绕过

查看低级的CSP配置

img

配置了 unsafe-inline ,允许行内代码执行,但是有 nonce 指定的值,我们只需要内嵌该值即可绕过

查看注入点

img

绕过
<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(123)</script>

高级绕过

查看低级的CSP配置

img

只能执行内部脚本,感觉没头绪

查看注入点

点击按钮后有一个jsonp的请求继续查找

img

绕过

Yakit 抓包,抓jsonp.php的数据包,修改callback的值,放包即可

image-20241016112057498

五、 其他安全响应头

session的cookie安全配置

局部设置
<?php ini_set("session.cookie_httponly",1)?>
全局设置

修改 /opt/lampp/etc/php.ini 中 session.cookie_httponly 的值为 On

个性化cookie
setcookie("mycookie", "123", time() + 36000, "/", "www.dlrb.com", false, false);

X-Content-Type-Options

这是一个 HTTP 响应头,用来指示浏览器不应该进行 MIME 类型探测(MIME sniffing)。

当这个响应头被设置时,它会告诉浏览器遵守在 Content-Type 头中发送的 MIME 类型。

如果 Content-Type 头中指定的类型是 “text/html”,那么浏览器会只以 HTML 的方式解析内容,即使实际的内容可能是 JavaScript。

在没有这个响应头的情况下,一些浏览器会尝试根据实际的内容或资源的开始几个字节来猜测内容的类型。这种行为在某些情况下可能导致安全漏洞。

例如,如果一个攻击者能够上传一个带有可执行代码的文本文件到一个不正确地配置了 MIME 类型的服务器,浏览器可能会将该文本文件当作一个脚本来执行。

通过设置 X-Content-Type-Options: nosniff,开发者可以较为安全地防止浏览器执行不应当执行的内容,减少一些基于 MIME 类型混淆的攻击,如驻留在服务器上的恶意软件尝试把自身伪装成图片或其他无害文件类型的情况。

这个设置特别对那些用户可以上传内容的网站来说非常重要,因为它有助于防止这些用户上传恶意文件,然后利用浏览器的 MIME 探测逻辑来执行它们。

X-XSS-Protection

这是一个 HTTP 响应头,旨在触发特定浏览器内置的跨站脚本(XSS)过滤功能。

这个过滤功能会检查服务器的响应,以寻找潜在的跨站脚本攻击。

X-XSS-Protection: 0 
这个设置指示浏览器关闭这个保护机制。
通常情况下,这个头部是用来打开 XSS 过滤并设置它的行为的,如下:

X-XSS-Protection: 1
启用 XSS 过滤(通常是浏览器的默认行为)。
如果检测到跨站脚本攻击,浏览器会尝试清理页面,移除不安全的部分。

X-XSS-Protection: 1; mode=block
不仅启用 XSS 过滤,而且如果检测到攻击,浏览器不会展示页面内容,而是会阻止页面加载。

然而,由于浏览器内置的这个机制并不总是有效,它可能会导致误报或未能检测到所有类型的 XSS 攻击

现代的浏览器和安全实践更推荐使用内容安全策略(Content Security Policy,CSP)来防护 XSS 攻击

因此,X-XSS-Protection 头部已经不被推荐使用,并且在现代浏览器中已经逐渐被淘汰了

当开发者确定他们的站点不依赖于浏览器的 XSS 过滤功能,并且他们已经有了更强的防护措施(如 CSP)时,他们可能会通过发送 X-XSS-Protection: 0 来禁用这个功能

这有助于避免可能的不一致行为,因为 XSS 过滤功能的实现在不同的浏览器之间可能会有所不同