You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hanami 2.2配置CSP nonce策略后,AJAX返回的JavaScript响应无法执行的问题求助

Hanami 2.2配置CSP nonce策略后,AJAX返回的JavaScript响应无法执行的问题求助

我现在在维护一个基于Hanami 2.2的Web应用,已经在config/app.rb里用nonce策略配置了内容安全策略(CSP),允许内联脚本执行:

config.actions.content_security_policy[:script_src] = "'self' 'nonce'"

页面加载时,通过Hanami的stylesheet_tag和javascript_tag生成的资源标签都会自动带上nonce,浏览器能正常加载CSS和JS资源,页面源码片段如下:

<html lang='en'>
<head>
  <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'>
  <meta charset='UTF-8'>
  <meta content='width=device-width, initial-scale=1.0' name='viewport'>
  <meta name="csrf-param" content="_csrf_token">
  <meta name="csrf-token" content="4111c46fb6a45da9dfea2ccd8521256f7f1c3852fbedc890d2ed56dc4111b7c9">
  <link href="/assets/app.css" type="text/css" rel="stylesheet" nonce="iWzsbPAkiB//CnB0">
</head>
<body>
  <!-- 页面内容 -->
  <script src="/assets/app.js" type="text/javascript" nonce="iWzsbPAkiB//CnB0"></script>
</body>
</html>

现在遇到了一个棘手的问题:我有个页面上的简单表单(包含两个文本输入框),需要通过jQuery AJAX提交,并且希望服务器返回的JS代码能直接执行。我在app/templates/home/create.js.haml里写了这样的代码:

%script{ nonce: content_security_policy_nonce }
  :plain
    alert("Hello");

这个逻辑和Rails里返回JS响应的思路类似,但实际测试时出了问题:

  • AJAX请求的头信息正常,包含Accept: */*和Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • 服务器返回的响应头里,CSP的script-src也正确带上了对应的nonce:
    Content-Security-Policy: base-uri 'self';child-src 'self';connect-src 'self';default-src 'none';font-src 'self';form-action 'self';frame-ancestors 'self';frame-src 'self';img-src 'self' https: data:;media-src 'self';object-src 'none';script-src 'self' 'nonce-iWzsbPAkiB//CnB0';style-src 'self' 'unsafe-inline' https:
    Content-Type: application/javascript; charset=utf-8
    
  • 响应体里的内容也正确带上了和CSP一致的nonce:
    <script nonce='iWzsbPAkiB//CnB0'>
      alert("Hello");
    </script>
    

但浏览器就是不执行这段脚本,控制台里报CSP错误:

Content-Security-Policy: The page’s settings blocked an inline script (script-src-elem) from being executed because it violates the following directive: “script-src 'self' 'nonce-iWzsbPAkiB//CnB0'”

明明nonce完全一致,为什么还是被拦截了?

我还测试了两种其他情况:

  1. 如果把CSP改成允许unsafe-inline:

    config.actions.content_security_policy[:script_src] = "'self' 'unsafe-inline'"
    

    同时把create.js.haml改成直接写脚本内容:

    :plain
      alert("Hello");
    

    这时响应体里只有alert("Hello");,脚本能正常执行,但unsafe-inline相当于放弃了CSP的安全防护,我不想用这种方案。

  2. 如果用Haml的:javascript标签来写:

    :javascript
      alert("Hello");
    

    响应体里会生成不带nonce的<script>标签,而且浏览器会报语法错误:

    Uncaught SyntaxError: expected expression, got '<'

我已经查了不少相关问题,尝试了各种社区建议但都没解决问题。现在实在没思路了,有没有大佬能告诉我接下来该排查什么?


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 08:43:04