您现在的位置是:网站首页 > 使用 CSP 防止点击劫持文章详情

使用 CSP 防止点击劫持

什么是点击劫持

点击劫持(Clickjacking)是一种视觉欺骗攻击手段。攻击者通过透明或伪装的iframe覆盖在目标网页上,诱使用户在不知情的情况下点击恶意内容。例如,攻击者可能将一个透明的按钮覆盖在"点赞"按钮上,用户以为自己点击的是点赞,实际触发了转账操作。

<!-- 恶意网站代码示例 -->
<style>
  iframe {
    opacity: 0.5;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 999;
  }
</style>
<iframe src="https://victim-bank.com/transfer"></iframe>

CSP 如何防御点击劫持

内容安全策略(Content Security Policy,CSP)通过HTTP响应头控制资源加载行为。针对点击劫持,CSP提供了frame-ancestors指令,可以限制页面被哪些父级页面嵌入。

Content-Security-Policy: frame-ancestors 'none'

这个策略会阻止所有框架嵌套尝试,包括iframe、frame、object等元素。当恶意网站尝试嵌入受保护的页面时,浏览器会拒绝加载。

常用 CSP 点击劫持防护策略

完全禁止嵌套

最严格的防护策略是禁止任何形式的框架嵌套:

Content-Security-Policy: frame-ancestors 'none'

允许同源嵌套

如果业务需要内部框架嵌套,可以限制为同源:

Content-Security-Policy: frame-ancestors 'self'

允许特定域名嵌套

对于需要跨域嵌入的场景,可以指定白名单:

Content-Security-Policy: frame-ancestors https://trusted.example.com https://partner.site.org

与其他安全头配合使用

CSP可以与传统的X-Frame-Options头一起使用,提供向后兼容性:

Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY

X-Frame-Options只支持三个值:

  • DENY:完全禁止嵌入
  • SAMEORIGIN:允许同源嵌入
  • ALLOW-FROM uri:允许指定URI嵌入(已废弃)

实际部署示例

Express 中间件配置

const express = require('express');
const helmet = require('helmet');

const app = express();

app.use(helmet.frameguard({ action: 'deny' }));
// 或使用CSP
app.use(helmet.contentSecurityPolicy({
  directives: {
    frameAncestors: ["'none'"]
  }
}));

Nginx 配置

add_header Content-Security-Policy "frame-ancestors 'none'";
add_header X-Frame-Options "DENY";

Apache 配置

Header always set Content-Security-Policy "frame-ancestors 'none'"
Header always set X-Frame-Options "DENY"

测试防护效果

部署后可以通过以下方式测试:

  1. 创建测试HTML文件尝试嵌入受保护页面
<!DOCTYPE html>
<html>
<body>
  <iframe src="https://your-protected-site.com"></iframe>
</body>
</html>
  1. 使用浏览器开发者工具查看控制台错误信息
  2. 使用在线CSP验证工具检查策略有效性

常见问题与解决方案

业务需要iframe嵌入怎么办

如果业务确实需要被第三方网站嵌入,应该:

  1. 明确列出所有允许的域名
  2. 定期审核这些域名的安全性
  3. 考虑使用postMessage进行安全通信
Content-Security-Policy: frame-ancestors https://partner1.com https://partner2.com

旧浏览器兼容性问题

对于不支持CSP的旧浏览器:

  1. 同时使用X-Frame-Options
  2. 考虑JavaScript防御方案作为补充
// 备用JavaScript防御
if (top !== self) {
  top.location = self.location;
}

误报问题处理

如果合法流量被拦截:

  1. 检查是否有重定向导致源变化
  2. 验证所有子域名的包含情况
  3. 使用报告机制收集错误
Content-Security-Policy: frame-ancestors 'self'; report-uri /csp-violation-report-endpoint

CSP 报告机制

启用报告功能可以帮助发现潜在问题:

Content-Security-Policy: frame-ancestors 'self'; report-uri https://your-domain.com/csp-report

服务器端处理示例(Node.js):

app.post('/csp-report', (req, res) => {
  console.log('CSP Violation:', req.body);
  res.status(204).end();
});

移动端特殊考虑

移动WebView可能需要额外配置:

  • Android WebView需要启用CSP支持
  • iOS WKWebView默认支持CSP
  • 混合应用要确保原生代码不会绕过策略

性能影响评估

CSP对性能的影响主要来自:

  1. 策略解析时间(通常可以忽略)
  2. 报告发送开销(在高流量站点需要注意)
  3. 预加载扫描器可能无法处理复杂策略

优化建议:

  • 保持策略简洁
  • 对静态资源使用单独的策略
  • 考虑使用meta标签作为补充
<meta http-equiv="Content-Security-Policy" content="frame-ancestors 'none'">

与其他安全策略的协同

CSP应该与以下安全措施配合使用:

  1. 同源策略(Same-Origin Policy)
  2. 跨域资源共享(CORS)配置
  3. 子资源完整性(SRI)检查
  4. 安全的Cookie属性(Secure, HttpOnly, SameSite)

完整的安全头示例:

Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(self)

框架特定配置

React 应用配置

在React中可以通过自定义服务器中间件或webpack插件添加CSP:

// webpack.config.js
const { DefinePlugin } = require('webpack');

module.exports = {
  plugins: [
    new DefinePlugin({
      'process.env.CSP_HEADER': JSON.stringify("frame-ancestors 'none'")
    })
  ]
}

Vue CLI 配置

vue.config.js中配置安全头:

module.exports = {
  devServer: {
    headers: {
      'Content-Security-Policy': "frame-ancestors 'none'"
    }
  }
}

Angular 配置

在angular.json中配置响应头:

{
  "projects": {
    "your-app": {
      "architect": {
        "serve": {
          "options": {
            "headers": {
              "Content-Security-Policy": "frame-ancestors 'none'"
            }
          }
        }
      }
    }
  }
}

监控与维护

有效的CSP策略需要持续维护:

  1. 定期审查策略是否仍然符合业务需求
  2. 监控CSP违规报告
  3. 随着业务发展调整白名单
  4. 在新功能上线前测试CSP兼容性

建议的监控方案:

// 前端监控代码示例
document.addEventListener('securitypolicyviolation', (e) => {
  analytics.send('CSP Violation', {
    violatedDirective: e.violatedDirective,
    blockedURI: e.blockedURI,
    lineNumber: e.lineNumber
  });
});

高级防护技术

对于高安全要求的应用,可以考虑:

动态策略生成

根据请求特征生成不同的策略:

app.use((req, res, next) => {
  if (req.path.startsWith('/admin')) {
    res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  } else {
    res.setHeader('Content-Security-Policy', "frame-ancestors 'self'");
  }
  next();
});

结合用户认证

对已认证用户应用更严格的策略:

app.use((req, res, next) => {
  if (req.user && req.user.isAdmin) {
    res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  }
  next();
});

非浏览器环境处理

识别并阻止非浏览器访问:

app.use((req, res, next) => {
  const userAgent = req.get('User-Agent');
  if (!userAgent || !isBrowser(userAgent)) {
    res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  }
  next();
});

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步