[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"content-frontend-recent-safety-tech":3,"$fcgx0ywf2wsmf":23},{"id":4,"type":5,"slug":6,"title":7,"date":8,"category":9,"tags":10,"body_markdown":14,"permalink":15,"excerpt_src":16,"media_type":16,"media_title":16,"media_author":16,"media_url":16,"rating":16,"layout":16,"pv":17,"admin_only":17,"created_at":18,"updated_at":18,"deleted_at":16,"status":19,"html":20,"excerpt":21,"cover":22},169,"article","frontend-recent-safety-tech","一些比较新的前端安全相关的技术点","2017-05-18 15:06","web",[11,12,13],"安全","JavaScript","HTTP","\n> 本文为[《Web前后端漏洞分析与防御》](https:\u002F\u002Fcoding.imooc.com\u002Fclass\u002F104.html)课程的配套文章。早年在慕课社区发布，现补发在博客上。\n\n一说到安全，大家总会特别敏感，尤其是有相当部分的前端开发者并不了解安全相关的知识，颇有谈虎色变的感觉。具体到前端安全这个话题呢，又有些说不清道不明，因为大部分的防御方案，总少不了后端的参与，也有开发者慢慢觉得好像安全都应该由后端来关注了。\n\n其实不然，起码 XSS CSRF 这一类的安全问题前端是一定要了解它们的原理和防御方法的。从防御方法上来说，XSS 和 CSRF 的防御在业界都有比较成熟的方案了。本文将记录一些比较新的防御方案，可能有一些比较老的书籍或者文章中不会提及这些方法。\n\n\u003C!-- more -->\n\n## XSS\n\nXSS 全称 Cross Site Scripting ，跨站脚本攻击，因为 CSS 这名字老早就被样式表拿走了，大家都在 web 这个领域，重名又不好看，所以只好起了个名字叫 XSS 了。说实话从 XSS 干的事来讲，其实并不太理解为什么有个“跨站”在里面，如果一定要强行解释的话，大概是因为有可能会运行一个来自别人网站的脚本，把这个脚本叫“跨站”了吧。\n\n好了，不重要。\n\n重要的是它是谁，它从哪里来，要到哪里去……这样的哲学问题有点难回答。我们换一个，重要的是它是什么鬼，能干什么，怎么防。\n\n### XSS 是什么鬼\n\n玩游戏的人都知道在游戏中经常出现一些奇葩的名字，比如“星辰并亲了他一口”，看上去一脸不知道什么鬼，但是当他有点事的时候，你就觉得好玩了，比如公会老大邀请他，就会有一条消息“公会老大邀请了星辰并亲了他一口”，然后一公会的人哄堂大笑。\n\n其实这种案例用专业的术语来说，就叫 XSS 了……\n\n本来“公会老大邀请了XX”这样一个句式，只希望XX是一个不会引起误会的名字而已，结果因为有一个奇葩名字，直接改变了整句话的意思，引介出了意外的含义。\n\nXSS 也是同样的东西，比如我只想在页面上显示一个名字：\n\n```html\n\u003Cspan class=\"name\">{{name}}\u003C\u002Fspan>\n```\n\n但是，如果我的名字是长这样的：\n\n```\n星辰\u003Cscript>alert('SB')\u003C\u002Fscript>\n```\n\n这时候就好玩了：\n\n```html\n\u003Cspan class=\"name\">星辰\u003Cscript>alert('SB')\u003C\u002Fscript>\u003C\u002Fspan>\n```\n\n你看，页面中凭空多了一段脚本。这个例子还算善良的，只是弹出来骂了你一句……\n\n“难道他还能弹出来打我？”\n\n呃……当然不是啦，但是人家可以偷偷干坏事啊。你说说，你都用JS干嘛？用户登录用的JS吧，读取资料用的JS吧，点击买东西、消费用的JS吧，查用户有多少钱用的JS吧，基于 Cookies 也可以读写吧。好的，你用JS能干的事情人家都能干。\n\n没事偷你个登录态，帮用户消费两块钱，查下你用户手机号是多少……接下来的事情我就不说了（无非就是前端程序员要背锅离职呗？）\n\n### XSS 怎么防御\n\n一个经典的防御方法就是对内容进行转义和过滤，比如\n\n```javascript\nvar escapeHtml = function(str) {\n\tif(!str) return '';\n\tstr = str.replace(\u002F&\u002Fg, '&amp;');\n\tstr = str.replace(\u002F\u003C\u002Fg, '&lt;');\n\tstr = str.replace(\u002F>\u002Fg, '&gt;');\n\tstr = str.replace(\u002F\"\u002Fg, '&quto;');\n\tstr = str.replace(\u002F'\u002Fg, '&#39;');\n\t\u002F\u002F str = str.replace(\u002F \u002Fg, '&#32;');\n\treturn str;\n};\n\nvar name = escapeHtml(`\u003Cscript>alert('SB')\u003C\u002Fscript>`);\n```\n\n此时 name 会变成\n\n```\n&lt;script&gt;alert(&#39;SB&#39;)&lt;\u002Fscript&gt;\n```\n\n这样就会原样显示出来，再也无法耍流氓啦。\n\n当然，富文本还要更麻烦一些，因为要保留一部分标签和属性，要不然全变纯文本了，就不富了。这种情况一般通过黑名单进行过滤，或者白名单放行。即只允许一部分指定的标签和属性，其它的全部转义掉。\n\n### CSP 大法\n\n前面转义的方法的出发点，是让用户的输入不要变成程序，输入的什么就让它输出成什么。\n\n事实上现代浏览器为我们带来了一个全新的安全策略，叫作内容安全策略，Content Security Policy，简称CSP。CSP的思路跟转义不一样，它的着手点是，如果一段代码变成了程序，我们是否应该运行它。或者更准确一点说，它实际上是定义页面上哪一些内容是可被信任的，哪一些内容是不被信任的。\n\n因为我们自己的脚本是预先就知道并放在页面上的，所以我们可以设置好信任关系，当有 XSS 脚本出现时，它并不在我们的信任列表中，因此可以阻止它运行。\n\n它的具体使用方式是在 HTTP 头中输出 CSP 策略：\n\n```\nContent-Security-Policy: \u003Cpolicy-directive>; \u003Cpolicy-directive>\n```\n\n从语法上可以看到，一个头可以输出多个策略，每一个策略由一个指令和指令对应的值组成。指令可以理解为指定内容类型的，比如`script-src`指令用于指定脚本，`img-src`用于指定图片。值则主要是来源，比如某个指定的URL，或者`self`表示同源，或者`unsafe-inline`表示在页面上直接出现的脚本等。\n\n详细的指令和值，可以查看[MDN相关页面](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FHeaders\u002FContent-Security-Policy)。\n\n具体到上面的 XSS 例子，可以使用\n\n```\nContent-Security-Policy: script-src 'self';\n```\n\n这样除了在同一个域名下的JS文件外，其它的脚本都不可以执行了，自然之前 XSS 的内容也就失效啦。简单粗暴有没有？\n\n当然，如果你说，我就是要在页面中放点内联的脚本，不可以么？当然可以啦，CSP 设计的时候也考虑了这些情况，还是相当灵活的。你只需要指定一个 nonce 属性，或者计算一下 hash 值，即可。详细的用法看 [MDN](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FHeaders\u002FContent-Security-Policy\u002Fscript-src) 哦。\n\n说实话，用 CSP 来处理 XSS 攻击还是不如转义来得优雅，因为转义可以不影响用户输入输出，不改变内容的本质。但是 CSP 提供了足够简单而又灵活的方式来防御 XSS ，可以很好地作为我们前端 XSS 防御的最后一道防线。\n\n## CSRF\n\nCSRF 也是个望文生不到义的词，它的全称是 Cross Site Request Foggy，即跨站请求攻击。虽然也有跨站，但我觉得这个跨站还是相当可以理解的，它真的是从别的网站发起一个请求到我们的网站的。\n\n当一个用户登录我们的网站后，在 Cookies 中会存放用户的身份凭证。在大部分时候，就是一个 SessionId 。当用户下次访问我们的网站的时候，我们用这个凭证识别出用户是谁，有没有登录态。\n\n如果第三方网站的代码请求了我们的网站，会发生什么呢？比如\n\n```html\n\u003Cimg src=\"http:\u002F\u002Fwww.example.com\u002Fhaha\" \u002F>\n```\n\n虽然它是一张图片，但它确实向`www.example.com`发了一个请求，如此用户有登录态的话，其实就相当于是用户自己发了一个请求。如果这个地址是一个发表文章、发布微博甚至转账之类的链接，那用户就在不知情的情况下进行了一些操作。这也是比较严重的安全问题。\n\n当然你可能会说，现在谁还这么弱智，把这么敏感的操作用 GET 啊？没错，你可以选择用 POST ，但是这丝毫不能阻止 CSRF 攻击的发生啊。\n\n```html\n\u003Ciframe name=\"test\">\u003C\u002Fiframe>\n\u003Cform target=\"test\" method=\"post\" action=\"http:\u002F\u002Fwww.example.com\u002Fhaha\">\n    ...\n\u003C\u002Fform>\n```\n\n当这个表单提交的时候，我们就发了一个 POST 请求。华丽丽的 CSRF 。\n\n### CSRF 的常规防御\n\nCSRF 比较常规的防御方式是通过判断来源和加 token。\n\n判断来源比较简单，主要是判断`referer`这个头，如果不是自己的网站，就返回错误。\n\n加 token 即同样的随机 token，在 cookies 中放一份，在表单中再放一份。这样第三方网站就无法获取到这个 token 是什么。\n\n但是这样做也有一个比较明显的问题，就是无法保证站内用户的体验。虽然你防了站外的攻击，但是也降低了站内用户的体验。具体表现在如果同时打开多个表单，只有最后一个表单能成功提交。\n\n### same-site 的 Cookie\n\n回想 CSRF 之所以能够攻击成功，核心原因就在于用户的身份是放在 Cookies 中的，而不管你通过什么方式访问网站，都会带上这个网站的 Cookies ，从第三方来的访问自然也不能例外。\n\n但是，Chrome 在这个问题上给了我们不同的答案，可以放第三方访问时不带 Cookies 。也就是说 Cookies 只有本站能用，来自第三方的访问都不能使用。\n\n具体的使用方式，是在打 Cookie 的时候，加上一个属性：`SameSite`，它的值有两：\n\n- `strict` 任何来自第三方的请求都不能使用 Cookies ，包括通过链接点进来的\n- `lex` 只有比较敏感的操作不带 Cookies ，比如表单提交\n\n针对 CSRF ，我们可以将 Cookies 设置成`SameSite: strict`的，这样就可以有效防御 CSRF 了。不过比较可惜的是，目前只有 Chrome 才支持这一属性。希望未来所有浏览器都能跟上脚步。\n\n> 使用 SameSite 还会面临一个问题，如果用户是点击链接进来的，那么是不能使用登录态的。一般可以考虑将用户不敏感的信息不设置这个属性，点进来仍然可以显示当前用户是谁，但是在请求的时候要求一个比较敏感的 SameSite 的 Cookies。这里需要更多的实践经验来探索。\n\n## 小结\n\n本文重点讲了 XSS 和 CSRF 这两种比较常见的前端安全问题的防御思路，尤其是如何使用一些新的规范、实现来帮助我们进行防御。希望后面浏览器对这些安全相关防御办法的普及率能再高一些，让前端工程师能花更少的时间写出更安全的代码。\n","\u002Farticle\u002Ffrontend-recent-safety-tech.html",null,0,"2026-08-28 04:37:17","published","\u003Cblockquote>\n\u003Cp>本文为\u003Ca href=\"https:\u002F\u002Fcoding.imooc.com\u002Fclass\u002F104.html\">《Web前后端漏洞分析与防御》\u003C\u002Fa>课程的配套文章。早年在慕课社区发布，现补发在博客上。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>一说到安全，大家总会特别敏感，尤其是有相当部分的前端开发者并不了解安全相关的知识，颇有谈虎色变的感觉。具体到前端安全这个话题呢，又有些说不清道不明，因为大部分的防御方案，总少不了后端的参与，也有开发者慢慢觉得好像安全都应该由后端来关注了。\u003C\u002Fp>\n\u003Cp>其实不然，起码 XSS CSRF 这一类的安全问题前端是一定要了解它们的原理和防御方法的。从防御方法上来说，XSS 和 CSRF 的防御在业界都有比较成熟的方案了。本文将记录一些比较新的防御方案，可能有一些比较老的书籍或者文章中不会提及这些方法。\u003C\u002Fp>\n\u003Ch2>XSS\u003C\u002Fh2>\n\u003Cp>XSS 全称 Cross Site Scripting ，跨站脚本攻击，因为 CSS 这名字老早就被样式表拿走了，大家都在 web 这个领域，重名又不好看，所以只好起了个名字叫 XSS 了。说实话从 XSS 干的事来讲，其实并不太理解为什么有个“跨站”在里面，如果一定要强行解释的话，大概是因为有可能会运行一个来自别人网站的脚本，把这个脚本叫“跨站”了吧。\u003C\u002Fp>\n\u003Cp>好了，不重要。\u003C\u002Fp>\n\u003Cp>重要的是它是谁，它从哪里来，要到哪里去……这样的哲学问题有点难回答。我们换一个，重要的是它是什么鬼，能干什么，怎么防。\u003C\u002Fp>\n\u003Ch3>XSS 是什么鬼\u003C\u002Fh3>\n\u003Cp>玩游戏的人都知道在游戏中经常出现一些奇葩的名字，比如“星辰并亲了他一口”，看上去一脸不知道什么鬼，但是当他有点事的时候，你就觉得好玩了，比如公会老大邀请他，就会有一条消息“公会老大邀请了星辰并亲了他一口”，然后一公会的人哄堂大笑。\u003C\u002Fp>\n\u003Cp>其实这种案例用专业的术语来说，就叫 XSS 了……\u003C\u002Fp>\n\u003Cp>本来“公会老大邀请了XX”这样一个句式，只希望XX是一个不会引起误会的名字而已，结果因为有一个奇葩名字，直接改变了整句话的意思，引介出了意外的含义。\u003C\u002Fp>\n\u003Cp>XSS 也是同样的东西，比如我只想在页面上显示一个名字：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;span class=&quot;name&quot;&gt;{{name}}&lt;\u002Fspan&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>但是，如果我的名字是长这样的：\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>星辰&lt;script&gt;alert('SB')&lt;\u002Fscript&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>这时候就好玩了：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;span class=&quot;name&quot;&gt;星辰&lt;script&gt;alert('SB')&lt;\u002Fscript&gt;&lt;\u002Fspan&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>你看，页面中凭空多了一段脚本。这个例子还算善良的，只是弹出来骂了你一句……\u003C\u002Fp>\n\u003Cp>“难道他还能弹出来打我？”\u003C\u002Fp>\n\u003Cp>呃……当然不是啦，但是人家可以偷偷干坏事啊。你说说，你都用JS干嘛？用户登录用的JS吧，读取资料用的JS吧，点击买东西、消费用的JS吧，查用户有多少钱用的JS吧，基于 Cookies 也可以读写吧。好的，你用JS能干的事情人家都能干。\u003C\u002Fp>\n\u003Cp>没事偷你个登录态，帮用户消费两块钱，查下你用户手机号是多少……接下来的事情我就不说了（无非就是前端程序员要背锅离职呗？）\u003C\u002Fp>\n\u003Ch3>XSS 怎么防御\u003C\u002Fh3>\n\u003Cp>一个经典的防御方法就是对内容进行转义和过滤，比如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>var escapeHtml = function(str) {\n\tif(!str) return '';\n\tstr = str.replace(\u002F&amp;\u002Fg, '&amp;amp;');\n\tstr = str.replace(\u002F&lt;\u002Fg, '&amp;lt;');\n\tstr = str.replace(\u002F&gt;\u002Fg, '&amp;gt;');\n\tstr = str.replace(\u002F&quot;\u002Fg, '&amp;quto;');\n\tstr = str.replace(\u002F'\u002Fg, '&amp;#39;');\n\t\u002F\u002F str = str.replace(\u002F \u002Fg, '&amp;#32;');\n\treturn str;\n};\n\nvar name = escapeHtml(`&lt;script&gt;alert('SB')&lt;\u002Fscript&gt;`);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>此时 name 会变成\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>&amp;lt;script&amp;gt;alert(&amp;#39;SB&amp;#39;)&amp;lt;\u002Fscript&amp;gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>这样就会原样显示出来，再也无法耍流氓啦。\u003C\u002Fp>\n\u003Cp>当然，富文本还要更麻烦一些，因为要保留一部分标签和属性，要不然全变纯文本了，就不富了。这种情况一般通过黑名单进行过滤，或者白名单放行。即只允许一部分指定的标签和属性，其它的全部转义掉。\u003C\u002Fp>\n\u003Ch3>CSP 大法\u003C\u002Fh3>\n\u003Cp>前面转义的方法的出发点，是让用户的输入不要变成程序，输入的什么就让它输出成什么。\u003C\u002Fp>\n\u003Cp>事实上现代浏览器为我们带来了一个全新的安全策略，叫作内容安全策略，Content Security Policy，简称CSP。CSP的思路跟转义不一样，它的着手点是，如果一段代码变成了程序，我们是否应该运行它。或者更准确一点说，它实际上是定义页面上哪一些内容是可被信任的，哪一些内容是不被信任的。\u003C\u002Fp>\n\u003Cp>因为我们自己的脚本是预先就知道并放在页面上的，所以我们可以设置好信任关系，当有 XSS 脚本出现时，它并不在我们的信任列表中，因此可以阻止它运行。\u003C\u002Fp>\n\u003Cp>它的具体使用方式是在 HTTP 头中输出 CSP 策略：\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>Content-Security-Policy: &lt;policy-directive&gt;; &lt;policy-directive&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>从语法上可以看到，一个头可以输出多个策略，每一个策略由一个指令和指令对应的值组成。指令可以理解为指定内容类型的，比如\u003Ccode>script-src\u003C\u002Fcode>指令用于指定脚本，\u003Ccode>img-src\u003C\u002Fcode>用于指定图片。值则主要是来源，比如某个指定的URL，或者\u003Ccode>self\u003C\u002Fcode>表示同源，或者\u003Ccode>unsafe-inline\u003C\u002Fcode>表示在页面上直接出现的脚本等。\u003C\u002Fp>\n\u003Cp>详细的指令和值，可以查看\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FHeaders\u002FContent-Security-Policy\">MDN相关页面\u003C\u002Fa>。\u003C\u002Fp>\n\u003Cp>具体到上面的 XSS 例子，可以使用\u003C\u002Fp>\n\u003Cpre class=\"shiki\" style=\"background-color:#121212;color:#dbd7caee\" tabindex=\"0\">\u003Ccode>Content-Security-Policy: script-src 'self';\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>这样除了在同一个域名下的JS文件外，其它的脚本都不可以执行了，自然之前 XSS 的内容也就失效啦。简单粗暴有没有？\u003C\u002Fp>\n\u003Cp>当然，如果你说，我就是要在页面中放点内联的脚本，不可以么？当然可以啦，CSP 设计的时候也考虑了这些情况，还是相当灵活的。你只需要指定一个 nonce 属性，或者计算一下 hash 值，即可。详细的用法看 \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FHeaders\u002FContent-Security-Policy\u002Fscript-src\">MDN\u003C\u002Fa> 哦。\u003C\u002Fp>\n\u003Cp>说实话，用 CSP 来处理 XSS 攻击还是不如转义来得优雅，因为转义可以不影响用户输入输出，不改变内容的本质。但是 CSP 提供了足够简单而又灵活的方式来防御 XSS ，可以很好地作为我们前端 XSS 防御的最后一道防线。\u003C\u002Fp>\n\u003Ch2>CSRF\u003C\u002Fh2>\n\u003Cp>CSRF 也是个望文生不到义的词，它的全称是 Cross Site Request Foggy，即跨站请求攻击。虽然也有跨站，但我觉得这个跨站还是相当可以理解的，它真的是从别的网站发起一个请求到我们的网站的。\u003C\u002Fp>\n\u003Cp>当一个用户登录我们的网站后，在 Cookies 中会存放用户的身份凭证。在大部分时候，就是一个 SessionId 。当用户下次访问我们的网站的时候，我们用这个凭证识别出用户是谁，有没有登录态。\u003C\u002Fp>\n\u003Cp>如果第三方网站的代码请求了我们的网站，会发生什么呢？比如\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;img src=&quot;http:\u002F\u002Fwww.example.com\u002Fhaha&quot; \u002F&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>虽然它是一张图片，但它确实向\u003Ccode>www.example.com\u003C\u002Fcode>发了一个请求，如此用户有登录态的话，其实就相当于是用户自己发了一个请求。如果这个地址是一个发表文章、发布微博甚至转账之类的链接，那用户就在不知情的情况下进行了一些操作。这也是比较严重的安全问题。\u003C\u002Fp>\n\u003Cp>当然你可能会说，现在谁还这么弱智，把这么敏感的操作用 GET 啊？没错，你可以选择用 POST ，但是这丝毫不能阻止 CSRF 攻击的发生啊。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>&lt;iframe name=&quot;test&quot;&gt;&lt;\u002Fiframe&gt;\n&lt;form target=&quot;test&quot; method=&quot;post&quot; action=&quot;http:\u002F\u002Fwww.example.com\u002Fhaha&quot;&gt;\n    ...\n&lt;\u002Fform&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>当这个表单提交的时候，我们就发了一个 POST 请求。华丽丽的 CSRF 。\u003C\u002Fp>\n\u003Ch3>CSRF 的常规防御\u003C\u002Fh3>\n\u003Cp>CSRF 比较常规的防御方式是通过判断来源和加 token。\u003C\u002Fp>\n\u003Cp>判断来源比较简单，主要是判断\u003Ccode>referer\u003C\u002Fcode>这个头，如果不是自己的网站，就返回错误。\u003C\u002Fp>\n\u003Cp>加 token 即同样的随机 token，在 cookies 中放一份，在表单中再放一份。这样第三方网站就无法获取到这个 token 是什么。\u003C\u002Fp>\n\u003Cp>但是这样做也有一个比较明显的问题，就是无法保证站内用户的体验。虽然你防了站外的攻击，但是也降低了站内用户的体验。具体表现在如果同时打开多个表单，只有最后一个表单能成功提交。\u003C\u002Fp>\n\u003Ch3>same-site 的 Cookie\u003C\u002Fh3>\n\u003Cp>回想 CSRF 之所以能够攻击成功，核心原因就在于用户的身份是放在 Cookies 中的，而不管你通过什么方式访问网站，都会带上这个网站的 Cookies ，从第三方来的访问自然也不能例外。\u003C\u002Fp>\n\u003Cp>但是，Chrome 在这个问题上给了我们不同的答案，可以放第三方访问时不带 Cookies 。也就是说 Cookies 只有本站能用，来自第三方的访问都不能使用。\u003C\u002Fp>\n\u003Cp>具体的使用方式，是在打 Cookie 的时候，加上一个属性：\u003Ccode>SameSite\u003C\u002Fcode>，它的值有两：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>strict\u003C\u002Fcode> 任何来自第三方的请求都不能使用 Cookies ，包括通过链接点进来的\u003C\u002Fli>\n\u003Cli>\u003Ccode>lex\u003C\u002Fcode> 只有比较敏感的操作不带 Cookies ，比如表单提交\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>针对 CSRF ，我们可以将 Cookies 设置成\u003Ccode>SameSite: strict\u003C\u002Fcode>的，这样就可以有效防御 CSRF 了。不过比较可惜的是，目前只有 Chrome 才支持这一属性。希望未来所有浏览器都能跟上脚步。\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp>使用 SameSite 还会面临一个问题，如果用户是点击链接进来的，那么是不能使用登录态的。一般可以考虑将用户不敏感的信息不设置这个属性，点进来仍然可以显示当前用户是谁，但是在请求的时候要求一个比较敏感的 SameSite 的 Cookies。这里需要更多的实践经验来探索。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Ch2>小结\u003C\u002Fh2>\n\u003Cp>本文重点讲了 XSS 和 CSRF 这两种比较常见的前端安全问题的防御思路，尤其是如何使用一些新的规范、实现来帮助我们进行防御。希望后面浏览器对这些安全相关防御办法的普及率能再高一些，让前端工程师能花更少的时间写出更安全的代码。\u003C\u002Fp>\n","\u003Cblockquote>\n\u003Cp>本文为\u003Ca href=\"https:\u002F\u002Fcoding.imooc.com\u002Fclass\u002F104.html\">《Web前后端漏洞分析与防御》\u003C\u002Fa>课程的配套文章。早年在慕课社区发布，现补发在博客上。\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp>一说到安全，大家总会特别敏感，尤其是有相当部分的前端开发者并不了解安全相关的知识，颇有谈虎色变的感觉。具体到前端安全这个话题呢，又有些说不清道不明，因为大部分的防御方案，总少不了后端的参与，也有开发者慢慢觉得好像安全都应该由后端来关注了。\u003C\u002Fp>\n\u003Cp>其实不然，起码 XSS CSRF 这一类的安全问题前端是一定要了解它们的原理和防御方法的。从防御方法上来说，XSS 和 CSRF 的防御在业界都有比较成熟的方案了。本文将记录一些比较新的防御方案，可能有一些比较老的书籍或者文章中不会提及这些方法。\u003C\u002Fp>\n","",{"total":17,"totalRoots":17,"comments":24,"pv":17},[]]