MST

星途 面试题库

面试题:Next.js 页面路由中的 CSRF 防护与路由安全性关联

说明 CSRF(跨站请求伪造)攻击对 Next.js 页面路由可能造成的危害,并详细描述如何在 Next.js 项目中结合 CSRF 防护机制来增强页面路由的安全性,例如从服务器端和客户端两方面进行防护的策略。
17.2万 热度难度
前端开发Next.js

知识考点

AI 面试

面试题答案

一键面试

CSRF 攻击对 Next.js 页面路由的危害

  1. 数据篡改:攻击者可能利用用户已登录的会话,伪造请求向 Next.js 应用的页面路由发送请求,执行一些修改数据的操作,比如修改用户个人资料、更改订单信息等,而用户对此毫不知情。
  2. 状态改变:未经授权改变应用的状态,例如在电商应用中,攻击者可能伪造请求取消用户的订单,影响用户正常的业务流程。
  3. 权限滥用:若用户具有某些高级权限,攻击者可以通过 CSRF 攻击利用这些权限执行恶意操作,如在管理页面创建新的管理员账号等。

Next.js 项目中结合 CSRF 防护机制增强页面路由安全性的策略

服务器端防护策略

  1. 使用 CSRF 令牌
    • 生成令牌:在服务器端,每次用户请求页面时生成一个唯一的 CSRF 令牌。例如,在 Next.js 的 API 路由中,可以使用加密库(如 crypto)生成一个随机字符串作为令牌。
    import crypto from 'crypto';
    
    const generateCSRFToken = () => {
        return crypto.randomBytes(32).toString('hex');
    };
    
    • 存储令牌:将生成的令牌存储在用户会话(session)中。在 Next.js 中,可以结合 next - iron - session 等库来管理会话。
    import Iron from 'next - iron - session';
    
    const session = Iron({
        password: process.env.SESSION_PASSWORD,
        cookieName: 'csrf - session',
        cookieOptions: {
            secure: process.env.NODE_ENV === 'production'
        }
    });
    
    export default async (req, res) => {
        await session(req, res);
        const csrfToken = generateCSRFToken();
        req.session.csrfToken = csrfToken;
        await req.session.save();
        res.json({ csrfToken });
    };
    
    • 验证令牌:当接收到用户的表单提交或其他可能受 CSRF 攻击影响的请求时,从请求头或表单数据中获取客户端传递的 CSRF 令牌,并与存储在会话中的令牌进行比对。
    import Iron from 'next - iron - session';
    
    const session = Iron({
        password: process.env.SESSION_PASSWORD,
        cookieName: 'csrf - session',
        cookieOptions: {
            secure: process.env.NODE_ENV === 'production'
        }
    });
    
    export default async (req, res) => {
        await session(req, res);
        const clientCSRFToken = req.body.csrfToken;
        const serverCSRFToken = req.session.csrfToken;
        if (clientCSRFToken === serverCSRFToken) {
            // 处理正常请求
        } else {
            res.status(403).json({ error: 'CSRF token verification failed' });
        }
    };
    
  2. 设置合适的 HTTP 头
    • Same - Site Cookie:设置 Set - Cookie 头的 Same - Site 属性,防止跨站请求时携带用户的会话 cookie。可以在 Next.js 中通过 next.config.js 进行配置。
    module.exports = {
        async headers() {
            return [
                {
                    source: '/(.*)',
                    headers: [
                        {
                            key: 'Set - Cookie',
                            value: 'sessionid=abcdef; Same - Site=strict'
                        }
                    ]
                }
            ];
        }
    };
    
    • Content - Security - Policy:通过设置 Content - Security - Policy 头,限制页面可以加载的资源来源,减少攻击者注入恶意脚本进行 CSRF 攻击的机会。同样在 next.config.js 中配置。
    module.exports = {
        async headers() {
            return [
                {
                    source: '/(.*)',
                    headers: [
                        {
                            key: 'Content - Security - Policy',
                            value: "default - src'self'"
                        }
                    ]
                }
            ];
        }
    };
    

客户端防护策略

  1. 在表单和请求中包含令牌
    • 页面渲染:在 Next.js 页面中,当渲染包含表单的页面时,从服务器获取 CSRF 令牌并嵌入到表单中作为隐藏字段。
    import React, { useEffect, useState } from'react';
    import { useRouter } from 'next/router';
    
    const MyForm = () => {
        const [csrfToken, setCSRFToken] = useState('');
        const router = useRouter();
    
        useEffect(() => {
            const fetchCSRFToken = async () => {
                const response = await fetch('/api/csrf - token');
                const data = await response.json();
                setCSRFToken(data.csrfToken);
            };
            fetchCSRFToken();
        }, []);
    
        const handleSubmit = (e) => {
            e.preventDefault();
            const formData = new FormData();
            formData.append('csrfToken', csrfToken);
            // 添加其他表单数据
            fetch('/api/submit - form', {
                method: 'POST',
                body: formData
            }).then((response) => {
                if (response.ok) {
                    router.push('/success');
                } else {
                    console.error('Form submission failed');
                }
            });
        };
    
        return (
            <form onSubmit={handleSubmit}>
                <input type="hidden" name="csrfToken" value={csrfToken} />
                {/* 其他表单字段 */}
                <button type="submit">Submit</button>
            </form>
        );
    };
    
    export default MyForm;
    
    • AJAX 请求:对于通过 fetch 或其他 AJAX 方式发送的请求,将 CSRF 令牌添加到请求头或请求体中。
    const csrfToken = 'your - csrf - token - here';
    fetch('/api/some - action', {
        method: 'POST',
        headers: {
            'Content - Type': 'application/json',
            'X - CSRF - Token': csrfToken
        },
        body: JSON.stringify({ someData: 'value' })
    });
    
  2. 避免在可跨站访问的资源中泄露敏感信息
    • 不要在 URL 中暴露敏感数据:避免在页面路由的 URL 中传递密码、令牌等敏感信息,因为这些信息可能被跨站请求获取到。
    • 限制第三方脚本访问:谨慎使用第三方脚本,确保它们不会在跨站环境中获取或篡改用户数据。对第三方脚本进行严格的安全审查,并且设置合适的权限和作用域。