Vue项目如何替换:href写法解决SonarQube安全扫描告警
问题本质
Vue中使用:href(即v-bind:href)绑定动态URL时,若未做校验,攻击者可构造javascript:onClick(恶意代码)格式的链接,用户点击后会直接在当前页面执行任意脚本,触发XSS风险,这也是SonarQube抛出该安全告警的核心原因。
当前业务场景的原始实现代码如下:
<el-table-column prop="link" width="70"> <template slot-scope="{row}"> <a :href="row.link" rel="opener" target="_blank" class="fast">{{row.link}}</a> </template> </el-table-column>
可落地修复方案
所有方案核心逻辑都是在URL绑定/跳转前做合法性校验,拦截危险协议,从根源消除注入风险,同时满足SonarQube的扫描规则要求。
方案1:前置URL安全校验,过滤危险协议
先封装通用的URL安全校验方法,仅允许业务需要的安全协议通过,非法链接直接拦截。// 通用安全URL校验工具 const checkSafeUrl = (url) => { if (!url) return false // 可根据业务需求调整允许的协议列表,默认禁止javascript、vbscript、data类危险协议 const allowProtocolList = ['http:', 'https:', 'ftp:', 'mailto:'] // 站内相对路径可直接放行,按需添加即可 // if (url.startsWith('/')) return true try { const parseUrl = new URL(url) return allowProtocolList.includes(parseUrl.protocol) } catch (err) { // 格式非法的URL直接判定为不安全 return false } }模板中绑定校验后的结果即可:
<el-table-column prop="link" width="70"> <template slot-scope="{row}"> <a :href="checkSafeUrl(row.link) ? row.link : 'javascript:void(0)'" rel="noopener noreferrer" target="_blank" class="fast" >{{row.link}}</a> </template> </el-table-column>方案2:点击事件代理跳转,不直接绑定动态值到href
把href固定为无风险的javascript:void(0),跳转逻辑放到点击事件中,跳转前先做安全校验,校验通过再调用原生API跳转。
模板部分:<el-table-column prop="link" width="70"> <template slot-scope="{row}"> <a href="javascript:void(0)" @click="handleLinkJump(row.link)" rel="noopener noreferrer" target="_blank" class="fast" >{{row.link}}</a> </template> </el-table-column>逻辑部分:
const handleLinkJump = (url) => { if (!checkSafeUrl(url)) return // 跳转时传入noopener参数,切断新页面与当前页面的opener关联,进一步规避风险 window.open(url, '_blank', 'noopener') }方案3:URL格式化强制安全前缀(适合固定跳转域名/协议的场景)
如果业务内所有跳转链接都是HTTP/HTTPS协议,可以直接对传入的URL做格式化处理,自动补全安全协议头,直接拦截危险协议开头的内容:const formatSafeUrl = (url) => { if (!url) return '' const trimUrl = url.trim() // 直接拦截危险协议开头的链接 if (/^(javascript|vbscript|data):/i.test(trimUrl)) return '' // 没有带协议头的链接默认补https前缀 if (!/^https?:\/\//i.test(trimUrl)) { return `https://${trimUrl}` } return trimUrl }模板中直接绑定格式化后的结果即可:
:href="formatSafeUrl(row.link)"
注意:前端校验属于第一层防御,后端在存储用户提交的链接时,也需要同步做URL合法性校验,多层防护才能彻底规避链接注入风险。另外使用
target="_blank"跳转外部链接时,不建议设置rel="opener",替换为rel="noopener noreferrer"可以避免新页面通过window.opener篡改原页面内容。
内容的提问来源于stack exchange,提问作者Tom Kale

