前端安全实践:常见攻击的防范与处理
"用户信息被盗了!"周一早上,运营总监急匆匆地冲进办公室。原来是有用户反馈自己的账号在不知情的情况下被他人登录了。作为前端负责人,我立即组织团队开展安全排查。
这次事件让我们意识到,前端安全不容忽视。虽然之前也做过一些安全防护,但显然还不够完善。今天就来分享一下我们是如何系统性地提升前端安全性的。
漏洞排查
首先对系统进行全面的安全扫描,很快发现了几个典型的安全隐患:
// 案例一:XSS 漏洞
function CommentList({ comments }) {
return (
<div>
{comments.map(comment => (
// 危险:直接渲染用户输入的内容
<div dangerouslySetInnerHTML={{ __html: comment.content }} />
))}
</div>
)
}
// 案例二:CSRF 漏洞
async function transferMoney(to, amount) {
// 危险:没有验证请求来源
const response = await fetch('/api/transfer', {
method: 'POST',
body: JSON.stringify({ to, amount })
})
return response.json()
}
// 案例三:敏感信息泄露
const config = {
apiKey: 'sk_live_xxxxx', // 危险:直接在前端暴露敏感信息
apiEndpoint: 'https://api.example.com'
}
安全加固
1. XSS 防护
// 1. 输入过滤
function sanitizeInput(input) {
return DOMPurify.sanitize(input, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong'],
ALLOWED_ATTR: ['title']
})
}
// 2. 安全的内容渲染
function CommentList({ comments }) {
return (
<div>
{comments.map(comment => (
<div key={comment.id}>
{/* 使用 React 的自动转义 */}
{comment.content}
{/* 如果必须渲染 HTML,先进行过滤 */}
<div dangerouslySetInnerHTML={{
__html: sanitizeInput(comment.richContent)
}} />
</div>
))}
</div>
)
}
// 3. CSP 配置
// 在 HTML 中添加
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';">
2. CSRF 防护
// 1. 添加 CSRF Token
const csrfToken = document.querySelector('meta[name="csrf-token"]').content
async function safeRequest(url, options = {}) {
const response = await fetch(url, {
...options,
headers: {
...options.headers,
'X-CSRF-Token': csrfToken
},
// 自动带上 cookie
credentials: 'include'
})
if (!response.ok) {
throw new Error('请求失败')
}
return response.json()
}
// 2. 验证请求来源
app.use((req, res, next) => {
const origin = req.get('Origin')
const referer = req.get('Referer')
// 验证请求来源
if (!isValidOrigin(origin) || !isValidReferer(referer)) {
return res.status(403).json({ error: '非法请求' })
}
next()
})
3. 敏感信息保护
// 1. 环境变量管理
// .env.production
VITE_API_ENDPOINT=https://api.example.com
VITE_PUBLIC_KEY=pk_live_xxxxx
// 配置文件
const config = {
apiEndpoint: import.meta.env.VITE_API_ENDPOINT,
publicKey: import.meta.env.VITE_PUBLIC_KEY
// 私钥等敏感信息只在服务端使用
}
// 2. 本地存储加密
const storage = {
set(key, value) {
const encrypted = CryptoJS.AES.encrypt(
JSON.stringify(value),
STORAGE_KEY
).toString()
localStorage.setItem(key, encrypted)
},
get(key) {
const encrypted = localStorage.getItem(key)
if (!encrypted) return null
const decrypted = CryptoJS.AES.decrypt(encrypted, STORAGE_KEY)
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8))
}
}
安全监控
为了及时发现安全问题,我们建立了安全监控系统:
class SecurityMonitor {
constructor() {
this.setupXSSMonitor()
this.setupCSRFMonitor()
this.setupSensitiveMonitor()
}
// 监控 XSS 攻击
setupXSSMonitor() {
// 监听 DOM 变化
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
// 元素节点
// 检查是否包含可疑的内联脚本
const scripts = node.getElementsByTagName('script')
Array.from(scripts).forEach(script => {
if (this.isSupiciousScript(script)) {
this.reportSecurityIssue('XSS', {
script: script.innerHTML,
url: window.location.href
})
}
})
}
})
})
})
observer.observe(document.body, {
childList: true,
subtree: true
})
}
// 监控 CSRF 攻击
setupCSRFMonitor() {
const originalFetch = window.fetch
window.fetch = async (url, options = {}) => {
if (this.isRiskRequest(url, options)) {
const hasToken = options.headers?.['X-CSRF-Token']
if (!hasToken) {
this.reportSecurityIssue('CSRF', {
url,
method: options.method
})
}
}
return originalFetch(url, options)
}
}
// 监控敏感信息
setupSensitiveMonitor() {
// 监控控制台输出
const originalConsole = { ...console }
Object.keys(originalConsole).forEach(key => {
console[key] = (...args) => {
if (this.containsSensitiveInfo(args)) {
this.reportSecurityIssue('SensitiveInfo', {
type: 'console',
args: this.maskSensitiveInfo(args)
})
}
originalConsole[key](...args)
}
})
}
reportSecurityIssue(type, data) {
// 发送安全告警
fetch('/api/security/report', {
method: 'POST',
body: JSON.stringify({
type,
data,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent
})
})
}
}
实践效果
通过这次安全加固:
- XSS 漏洞被完全修复
- CSRF 攻击得到有效防范
- 敏感信息得到妥善保护
- 安全事件响应更加及时
最让我印象深刻的是一位安全专家的评价:"这套防护体系已经达到了企业级应用的安全标准。"
经验总结
前端安全就像是给房子安装防盗系统,需要多层防护。关键是要:
输入过滤 - 永远不要信任用户输入访问控制 - 严格校验请求来源敏感防护 - 妥善保护敏感信息持续监控 - 及时发现安全隐患
写在最后
前端安全是一个持续的过程,需要我们不断学习和更新防护措施。就像那句话说的:"木桶的短板决定了水位的高度",任何一个安全漏洞都可能成为系统的致命弱点。
有什么问题欢迎在评论区讨论,让我们一起探讨前端安全的最佳实践!
如果觉得有帮助,别忘了点赞关注,我会继续分享更多实战经验~