ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

程序员必知:十大网络安全漏洞与工程化防御实践

程序员必知:十大网络安全漏洞与工程化防御实践 上周做代码评审一个同事拍着胸脯说这个接口没有安全问题我顺着他提交的改动往下翻了两行就看到前端传过来的参数被直接拼进了 SQL 字符串旁边还配了一句注释“这里走的是动态排序字段预编译参数化处理不了先拼一下”。类似的情况过去几年我在代码评审里见到过太多次。程序员必知的网络安全知识点说来说去其实就那么十来个反复出现的漏洞类型不是什么高深莫测的黑客技术更多是工程习惯问题。这篇我不讲攻击炫技只讲开发中真正能用上的十个方向威胁建模、SQL注入、密码存储、会话管理、越权控制、XSS、CSRF、文件上传、SSRF、供应链安全。适合刚接触安全的初中级后端、前端和全栈工程师也适合想在代码评审里主动发现风险的人。1. 先建立威胁模型程序员最该理解“攻击者”是谁1.1 攻击者的真实画像不是电影里的高手是扫描器和脚本很多程序员对网络安全的第一个误解是把攻击者想象成一个戴兜帽的高手坐在昏暗房间里盯着你的系统死磕。真实的攻击者不是这样的至少绝大多数攻击不是这样的。你只要把一个普通服务暴露到公网几小时内就会收到来自全球的自动化扫描流量这些流量在探测开放端口、尝试弱口令、试探已知漏洞像流水线一样批量运作。安全圈有句话叫“不是有人针对你而是大家都在被批量扫描”所以“我们系统没价值不会被攻击”这个想法非常危险。一台机器被攻破之后不一定是为了偷你的业务数据也可能只是被当成跳板去攻击别人或者被拉进挖矿程序里当免费算力。从工程视角看你不需要假设一个无所不能的敌人只需要假设有人会对你的系统做自动化批量尝试并且会利用所有你暴露出来的入口。这就是“攻击面”这个概念重要性的来源任何一个接收外部输入、响应外部请求的位置都是攻击面。表单提交是文件上传是回调 URL 是Webhook 是甚至一个用来生成 PDF 的接口也是。所以第一步不是急着学各种漏洞利用姿势而是先建立一个习惯每次写接口时把这个接口当成暴露在公网的东西来看然后问自己“如果这个接口被恶意调用会发生什么”。建立这种威胁模型视角比背诵十个漏洞定义更有用。1.2 STRIDE威胁建模一张表把风险聊清楚威胁建模不是安全专家的专利微软提出的 STRIDE 模型我到现在还在用因为它简单到可以画在一张表里。STRIDE 是六类威胁的首字母缩写伪造Spoofing、篡改Tampering、抵赖Repudiation、信息泄露Information Disclosure、拒绝服务Denial of Service、权限提升Elevation of Privilege。威胁类型含义典型场景伪造冒充他人身份登录接口被撞库、Token被伪造篡改修改数据或请求内容订单金额被改、请求参数被替换抵赖否认做过的事没有操作日志用户不承认下过单信息泄露不该看到的数据被看到越权访问他人订单拒绝服务让服务不可用接口被刷、压垮数据库权限提升普通用户获得管理员权限普通账号调用管理接口用法很简单拿一个核心业务流程比如登录模块逐条过一遍登录请求会不会被重放这是伪造用户资料能不能被改这是篡改操作有没有日志这是抵赖密码存的是不是明文这是信息泄露验证码接口能不能被刷爆这是拒绝服务普通用户能不能走管理员登录逻辑这是权限提升。不需要一次性把所有流程都分析完挑核心功能过一遍后面写代码时对“哪里容易出事”就会有一个本能的判断。我见过很多团队第一次做这个练习时会吓一跳原来自己系统里随手一数就有七八个没兜底的地方。2. 注入攻击最经典的漏洞家族至今仍排第一2.1 SQL注入参数化查询是底线不是可选项SQL 注入排在第一位不是因为它最高级而是因为它最常见而且一旦发生就是灾难级别的数据泄露。原理其实特别好理解你的程序把用户输入当成 SQL 语句的一部分去执行了。我用 Python 写个最典型的错误示范# 错误示范不要这样写 user_input request.form[username] sql SELECT * FROM users WHERE username user_input cursor.execute(sql)如果用户输入的 username 是admin OR 11拼接出来的 SQL 就变成了SELECT * FROM users WHERE username admin OR 11这个查询会返回全部用户如果后面还跟着更新语句后果完全可控不住。修复方式也很明确用参数化查询把 SQL 语句模板和参数分开传让数据库自己处理参数的转义和类型转换。改成参数化之后是这个效果# 正确做法参数化查询 sql SELECT * FROM users WHERE username %s cursor.execute(sql, (user_input,))参数化为什么有效因为数据库在执行参数化语句时已经预先解析好了 SQL 结构用户输入只会被当成数据不会被当成 SQL 指令。一句话概括你给数据库的是一份已经定好空位的菜单用户往里填的是食材食材永远不会变成菜单上的操作指令。需要补充的是ORM 也不能完全免死很多 ORM 提供了 raw query 或拼接查询的能力一旦用了就等于绕过了框架的安全保护。另外数据库账号的权限也要收紧应用层的账号只给增删改查的必要权限不要给 DROP 这类高危权限这算是纵深防御。2.2 命令注入与模板注入框架引入的新风险很多程序员以为不直接拼 SQL 就安全了其实注入攻击远不止 SQL 一种。命令注入发生在你把用户输入拼到系统命令里的时候比如有些后台功能需要 ping 一个 IP 或调用某个外部脚本# 错误示范命令拼接 import subprocess ip request.form[ip] result subprocess.run(fping -c 1 {ip}, shellTrue, capture_outputTrue)用户如果在 ip 里传入127.0.0.1; cat /etc/passwd就相当于让服务器执行了两条命令。修复的核心是两条能不调用系统命令就不调用必须调用时用参数列表方式而不是字符串拼接同时关闭 shell 中间层并用白名单校验输入。还有一类容易踩的坑是模板注入服务端模板渲染引擎把用户输入当成了模板代码。很多 Python 的 Server-Side Template Injection 漏洞就是用户在输入框里填入模板表达式结果被引擎执行了。防止这类问题原则是用户输入只允许作为数据出现永远不允许作为模板代码的一部分被渲染。模板引擎的沙箱也靠不住不能完全依赖。2.3 一个真实排查链路日志里的SQL语法错误有一回一个订单查询接口时不时返回 500报错日志里有一条 SQL syntax error。我们第一反应是数据问题结果把 SQL 打出来一看发现问题出在新增的排序功能上产品经理要求支持按多个字段排序开发图省事直接把前端传的 sort_field 拼进了 SQL 尾部 append 的排序子句。看起来人畜无害的“赋值写死”和“几个选项里选一个排序字段”最后因为接口要支持任意字段变成了一个隐藏的注入点。排查过程不复杂但很有代表性查日志定位到报错语句对比代码发现普通查询走了 ORM 的参数化唯独排序字段因为“参数化不了”用了字符串拼接。更麻烦的是我们在线下安全扫描里没有发现这个点因为扫描器很难自动猜出这个参数可以拼接。修复方案是典型的白名单映射排序字段先从一个允许列表里取值取不到就返回默认排序而不是把用户输入当成字段名直接用。# 修复思路排序字段白名单映射 ALLOWED_SORT_FIELDS { created_at: created_at, updated_at: updated_at, status: status, } sort_field ALLOWED_SORT_FIELDS.get(request.form.get(sort_field, created_at), created_at) # 排序方向也只允许 asc/desc direction request.form.get(direction, desc) direction direction if direction in (asc, desc) else desc这个案例给我的经验是安全修复和稳定性修复往往是同一件事。参数校验缺失导致的问题不只是安全风险还会让系统在异常输入下直接 500日志都被刷屏。写代码时多写一层白名单校验既防了注入也防了脏数据。3. 认证与会话安全登录功能是最值钱的攻击面3.1 密码存储哈希加盐不是加密登录模块是整个业务系统里攻击者最想拿下的地方而密码存储方式直接决定了用户数据泄露时的损失上限。很多程序员会把“加密”和“哈希”混为一谈其实这是两回事。加密是可逆的有密钥就能还原成明文所以数据库一旦泄露加密密码和明文差别不大哈希是不可逆的同一份输入每次输出的长度固定、结果固定但不应该能还原出原文。正确的密码存储方式是哈希加盐。哈希算法要选专门为密码设计的慢哈希算法比如 bcrypt、scrypt、Argon2不要用 MD5、SHA1 或者裸的 SHA256。这些普通哈希算得太快攻击者可以用 GPU 每秒算几十亿次再大的密码库都能被穷举。盐的作用是让同一个密码在不同用户那里产生完全不同的哈希结果从而破坏彩虹表和批量破解。bcrypt 的 cost 参数建议设置在 10 到 12 之间太低了容易被暴力破解太高了会拖慢正常登录响应。Python 里用 bcrypt 库写起来很简单import bcrypt # 注册时生成盐并哈希 password request.form[password].encode(utf-8) hashed bcrypt.hashpw(password, bcrypt.gensalt(rounds12)) # 登录时校验 is_valid bcrypt.checkpw(password, hashed)这里有个小坑bcrypt 只处理前 72 字节超过部分会被截断导致两个超长且前缀相同的密码可能被判定为同一个密码。处理方式可以是在哈希前先做一次 SHA-256 再交给 bcrypt但这需要统一方案不能一部分用户用旧逻辑一部分用新逻辑。如果系统里已经存了一批弱哈希甚至明文密码别等大版本可以先在登录流程里做无感升级用户登录成功时检测到旧哈希格式立刻用 bcrypt 重新哈希并更新存储下一次登录就用新算法校验了。3.2 会话与Token管理过期、刷新和固定会话登录之后系统怎么识别你是你这就是会话管理的问题。最基础的场景是 Session服务端给用户发一个 session_id存到 Cookie 里用户后续请求带上这个 ID。这里有几个容易被忽略的点session_id 的随机性要够强不能用自增数字或者可预测的短随机串登录成功之后必须重新生成 session_id防止会话固定攻击Cookie 要加上 HttpOnly、Secure、SameSite 属性。HttpOnly 是防止 JavaScript 读取 CookieSecure 是保证只在 HTTPS 下传输SameSite 是限制跨站请求携带 Cookie这三个属性可以在设置 Cookie 时直接带上。Token 体系里最流行的是 JWT但 JWT 的坑也最多。HS256 算法依赖一个服务端密钥这个密钥如果太弱就会被爆破过期时间如果设成 7 天甚至 30 天泄露一个 Token 等于泄露了长期访问权限很多实现里把 user_id 直接编码进 Token还不校验用户是否被禁用最要命的是很多系统根本没有退出登录的吊销机制Token 发出去了就收不回来。我建议的落地参数是短期 Access Token 15 分钟到 1 小时长期 Refresh Token 7 天Refresh Token 在刷新时必须轮换旧的直接作废Token 尽量放到 HttpOnly Cookie 里而不是 localStorage因为 localStorage 里的一点 XSS 就可能导致 Token 被偷而 Cookie 配合 HttpOnly 可以挡住这一条路。当然放到 Cookie 会带来 CSRF 的考量下一章会讲安全从来不是单点问题是层层叠加的问题。4. 权限与业务逻辑越权漏洞比注入更难防4.1 水平越权与垂直越权两个场景越权漏洞是我在实际业务系统里看到发生率最高的漏洞类型远高于注入。它的特点是不需要什么高深技巧纯粹是逻辑问题。水平越权指用户 A 操作了用户 B 的数据比如用户 A 登录后想查看订单详情请求里带上订单 ID后端直接按这个 ID 查库并返回# 错误示范只校验登录不校验归属 order_id request.form[order_id] order db.query_one(SELECT * FROM orders WHERE order_id %s, (order_id,)) return render_order(order)用户 A 只要把 order_id 换成 B 的订单号就能看到别人的订单。正确做法是多查一层归属条件查询时强制加上当前登录用户的 ID。垂直越权则是指普通用户调用了管理员的接口比如管理端接口没有校验角色只校验了登录状态普通用户只要能拿到管理接口的 URL 就能执行操作。修复的核心是每一个接口都要做身份与权限校验不能只做在菜单和路由上。越权类型错误场景修复要点水平越权通过遍历 ID 访问他人数据数据查询强制关联当前用户垂直越权普通用户调用管理员接口每个接口校验角色权限4.2 后端鉴权原则永远不要相信前端传参有些开发会在前端隐藏按钮、禁用操作入口、用路由守卫拦截页面以为这样后端就安全了。但这些全都可以绕过攻击者直接发请求就行根本不经过你的前端页面。后端的每个接口都必须在服务端独立做权限校验这是铁律。校验逻辑最好封装成统一的装饰器或中间件不要在每个接口里手写一遍否则很容易漏掉某一个接口。我见过一个后台系统列表接口校验了权限但导出 Excel 的接口忘了校验普通用户直接调导出接口把全量数据拖走了。这个教训我记到现在。权限模型上中小团队用 RBAC 就够给用户分配角色角色关联一组权限再复杂的场景可以上 ABAC根据用户、资源、环境等属性动态判断。但不管用什么模型核心原则是同一个每个请求到达后端时先问两个问题第一这个用户是谁第二这个用户对当前操作目标有没有权限。我自己的自测习惯是多准备两个普通测试账号专门用来互查数据模拟用户 A 访问用户 B 的资源场景一旦发现能查到对方的数据立刻定位后端逻辑问题。5. 浏览器侧攻击XSS、CSRF和浏览器安全机制5.1 XSS存储型、反射型、DOM型输出编码是关键XSS跨站脚本攻击的原理是攻击者的脚本被当成页面内容执行了。比如一个博客评论功能用户在评论里写了scriptalert(1)/script如果站点没有对评论做转义所有打开这个页面的用户都会执行这段脚本。危害远不止弹个框这么简单脚本可以窃取用户 Cookie、篡改页面内容、伪造登录框、在用户不知情的情况下发起请求。XSS 分存储型、反射型和 DOM 型。存储型是攻击脚本存进数据库每次访问都执行危害最大反射型是攻击脚本通过 URL 参数带入服务端没处理就原样返回页面DOM 型是攻击脚本在前端 DOM 操作中被执行不经过服务端。它们有一个共同点用户输入只有在进入页面时没有按内容类型做正确的编码转义才会变成可执行的脚本。修复思路分三层。第一层是输入侧做校验但输入校验只是辅助不能把它当主要防线因为有些场景就是允许用户输入特殊字符比如富文本编辑器。第二层是输出侧做编码这是真正的关键模板引擎默认会自动转义问题是很多人用了 innerHTML、v-html、dangerouslySetInnerHTML 这类接口相当于绕过转义让用户输入直接当 HTML 执行。第三层是兜底方案配置 CSP让浏览器只执行白名单里的脚本来源。5.2 CSRF同源策略为什么挡不住它CSRF跨站请求伪造是和 XSS 经常被一起提起但完全不同的漏洞。CSRF 的核心危害在于用户登录了银行网站 A然后又在另一个标签页打开了恶意网站 BB 页面上的脚本或表单向 A 发起请求浏览器会自动把 A 的 Cookie 带上。A 的服务器看到这个带 Cookie 的请求就认为是用户本人的操作于是转账、改密码、发帖全被攻击者“代劳”了。很多新手会问同源策略难道不管用吗这里有一个关键区别同源策略限制的是浏览器读取跨域响应但不限制发送请求。攻击者发一个表单提交确实读不到服务器的返回结果但操作已经发生了。要想判断这个 POST 请求是不是用户主动发起的需要另外的手段。修复 CSRF 的标准做法是使用 CSRF Token服务端在渲染表单时生成一个随机 Token 存进 Session用户提交时把 Token 一起带回来两边一致才放行。更省事儿的现代方案是设置 Cookie 的 SameSite 属性SameSiteLax 可以阻止大多数跨站请求携带 Cookie至少挡住 GET 以外的跨站提交SameSiteStrict 更严格但会影响一些正常的跨站跳转导航需要权衡。还有校验 Origin 和 Referer 的做法但这两个头有时会被浏览器限制或为空容易误伤所以 Token 仍然是主流。5.3 CSP与安全响应头给浏览器写一份安全白皮书CSP内容安全策略是浏览器提供的一套白名单机制通过响应头告诉浏览器这个页面只能加载哪些来源的脚本、样式、图片。一旦配置生效即使 XSS 能把脚本标签插进页面浏览器也会拒绝执行非白名单来源的脚本这是 XSS 的一道非常硬核的兜底防线。一个最小可用的 CSP 配置长这样Content-Security-Policy: default-src self; script-src self; object-src none; frame-ancestors none解读一下default-src self 表示所有资源默认只允许同源加载script-src self 表示脚本只能从本站加载object-src none 禁止插件frame-ancestors none 禁止被 iframe 嵌套这同时把点击劫持也挡掉了。实际项目里如果用了第三方统计脚本、CDN 资源、内联脚本CSP 配置会复杂一些所以上线时可以先加一个Content-Security-Policy-Report-Only头只收报告不拦截观察几天再切换成强制模式。除了 CSP几个常用的安全响应头也值得固定到网关层。X-Frame-Options 防点击劫持X-Content-Type-Options: nosniff 防止浏览器对响应类型进行猜测性解析Referrer-Policy 控制外链请求时携带多少 URL 信息。Nginx 里可以集中加上add_header X-Frame-Options SAMEORIGIN always; add_header X-Content-Type-Options nosniff always; add_header Referrer-Policy no-referrer-when-downgrade always;浏览器侧的防线是层层叠加的响应头只是最后一道闸门前面的输入校验、输出编码、Token 机制该做的都得做。只有一个原则不要指望单层防线挡住所有攻击。6. 入口级漏洞文件上传、SSRF与反序列化6.1 文件上传后缀检查远远不够文件上传功能是很多业务系统的标配头像、附件、导入模板都走这里但这也是攻击者特别喜欢试探的入口。最经典的攻击是把可执行脚本传上去并访问到它脚本在服务器上跑起来整个服务器就沦陷了。还有更隐蔽的玩法上传一个 HTML 文件到你的域名下利用同源关系做钓鱼上传一个恶意 SVG 文件里面内嵌脚本在有 SVG 渲染能力的页面里触发 XSS上传同名文件覆盖已有文件甚至狂传文件把存储空间塞满。后缀名黑名单基本是最弱的方案攻击者可以双写后缀、大小写绕过、上传无后缀文件再配合解析漏洞。正确的做法是一整套组合拳后缀名白名单只允许业务需要的图片或文档类型校验文件的真实 MIME 类型和文件头而不是只看 HTTP 请求里的 Content-Type给文件重新生成随机文件名彻底放弃用户传入的原始文件名文件存到独立的对象存储或与 Web 根目录隔离的目录并保证该目录不支持脚本执行限制单文件大小和总存储量。图片类上传最稳的是服务器重新解码一次图片相当于清洗了一遍但要注意不要解出超大图片把自己内存打爆。6.2 SSRF服务端请求被当成跳板SSRF服务端请求伪造是近几年讨论热度特别高的漏洞名字听着拗口但原理很直接服务端帮用户去请求了一个 URL而这个 URL 能被用户控制。常见的触发场景是 webhook 回调、图片抓取、URL 转 PDF、社交平台链接预览。用户把 URL 填进去服务端去访问如果没有任何限制服务端就成了攻击者的代理可以拿着你的服务器身份去扫描内网、访问云平台元数据服务。防御 SSRF 的核心思路是切断用户对目标地址的完全控制。做 URL 白名单是最先想到的方案但域名白名单会被 DNS 重绑定和重定向绕过所以还要组合限制协议只能 http/https在服务端做 DNS 解析后检查解析出的 IP 是否落在私网段不允许跟随重定向或者每次重定向都重新校验一次访问超时时间设短避免被用来拖慢服务。代码层面可以用 socket 先解析 IP 再判断import socket from urllib.parse import urlparse def check_url_allowed(url): hostname urlparse(url).hostname ip socket.gethostbyname(hostname) # 这里可以增加私网 IP 段判断如 10.x.x.x, 192.168.x.x, 172.16.x.x if is_private_ip(ip): raise ValueError(目标地址不允许访问) return ip这段代码只是示意真正的完整方案还需要考虑 IPv6、DNS 解析多个结果等细节。但核心思路很清楚不要让用户完全决定服务端该访问哪里。6.3 反序列化数据到对象的危险一跃反序列化漏洞是那种听起来很专业、实际影响也极大的问题。很多语言提供把对象序列化成字节流再恢复成对象的能力但反序列化过程中如果数据里包含了可触发的魔法方法、析构函数或构造链攻击者就可能构造一条调用链让服务端在恢复数据时执行任意代码。Java 的 ObjectInputStream、Python 的 pickle、PHP 的 unserialize 都属于这类高危接口。这类漏洞对程序员的启示不是让你去背利用链而是让你建立一条红线永远不要对不可信数据做原生反序列化。优先用 JSON、MessagePack 这类纯数据格式它们只表示数据没有代码执行能力。如果业务确实需要跨语言、跨版本的对象传输加一层签名校验保证数据来源可信同时在反序列化端做类的白名单限制只允许自定义的少数几个类被恢复。这里要特别提醒依赖库里的老版本反序列化实现也可能出问题升级依赖本身就是在补安全债。7. 供应链与工程化安全把安全从“运维的事”变成开发日常7.1 依赖漏洞开源组件里的定时炸弹很多程序员的眼里只有自己写的代码感觉自己写的部分没问题就安全了但实际上现代应用里 80% 以上的代码来自第三方依赖这些依赖里任意一个存在漏洞你的系统就跟着遭殃。之前影响面极大的日志组件漏洞只要项目里引入了受影响版本就可能中招哪怕你一行相关的业务代码都没写过。依赖管理不是选个包管理器就完事而是一条持续的安全检查流程。工具层面前端可以用 npm auditPython 可以用 pip-audit通用型的依赖检查工具推荐 OWASP Dependency-Check它在 CI 里能扫描 Java、.NET、Python 等多种项目的依赖并生成漏洞报告。GitHub 的 Dependabot 会自动检测已知漏洞并提交升级 PRSnyk 则是商业化做得比较成熟的依赖安全平台。工具适用场景特点npm auditNode.js 项目集成在 npm 中开箱即用pip-auditPython 项目命令行即可扫描OWASP Dependency-Check多语言项目开源免费适合 CI 集成DependabotGitHub 项目自动检测并提 PRSnyk多语言/容器覆盖广支持漏洞链路分析落地建议有几个依赖锁文件一定要入库保证所有人装到的版本完全一致升级依赖要纳入排期不能只在做新功能时顺手升企业里可以用私有仓库镜像做统一代理既方便内网安装也方便在中间层做一次版本控制。最近几年供应链安全的关注度越来越高国际上开始推行 SBOM 软件物料清单相当于把项目里每个依赖、每个组件都列成一份清单出问题的时候能快速定位影响范围。这个意识值得从现在就开始养。7.2 最小安全检查清单在CI和代码评审里落地安全要做进开发流程而不是等上线前找安全团队扫一遍。我建议每个项目至少在 CI 里加三道工序静态代码扫描SAST、依赖漏洞扫描、基础镜像扫描。静态扫描工具有很多比如 SonarQube、Semgrep它们能在代码提交后自动跑一遍发现明显的注入、硬编码密钥、危险函数调用问题。依赖扫描上面已经说过镜像扫描可以用 Trivy 或 Grype扫描出镜像里操作系统和第三方库的漏洞列表。除了工具代码评审时也可以有一份最小自查清单我把自己常用的十条列在这里可以直接抄登录相关密码是否用了慢哈希加盐是否校验旧密码强度。会话相关登录后是否重新生成 session_idToken 过期策略是否合理。权限相关每个后端接口是否都校验了当前用户身份和资源归属。注入相关所有外部输入是否都走了参数化排序、表名等特殊位置是否用了白名单。前端输出用户输入在渲染时是否被正确编码有没有绕过转义的危险 API。浏览器安全CSP、X-Frame-Options、X-Content-Type-Options 等响应头是否配置。文件上传后缀、MIME、文件头、随机文件名、存储隔离是否都做了。服务端请求URL 请求类接口是否限制了协议、目标 IP 和重定向。反序列化是否有对不可信数据的原生反序列化调用。依赖安全依赖锁文件是否入库CI 是否有依赖漏洞扫描。有一个容易被轻视的点是安全扫描和主动测试一定要在测试环境做而且要在授权范围内做。很多安全意识不错的团队想验证自己的系统结果在不该扫描的环境里跑了一遍扫描器给自己惹了麻烦。测试环境的验证、生产环境的主动扫描这两件事的边界要非常清晰生产环境的安全验证应该交给有授权的专业团队。最后说一个我的个人体会。真正让我从对安全无感变成下意识担心的不是看了多少漏洞报告而是某天半夜收到线上告警发现一个没人注意的内部工具接口被自动化脚本扫了一遍。那次之后我给自己定了一条规矩每次新建接口先把“这个接口被恶意调用会发生什么”写进实现代码的注释里再把出手权限校验和输入校验的失败路径写清楚。安全本质上不是一个独立岗位的职责也不是上线前的某个环节它只是代码评审清单里多出来的一行字。当你把它当成普通工程问题去处理时会发现并没有想象中那么难。
返回列表