跟我零基础跟完RSC反序列(1)

admin 2026-04-10 03:08:43 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文从React框架的next-action头部机制切入,分析了actionId的识别与转发流程。关键发现包括:通过serverActionsManifest映射action与worker关系,当本地无对应worker时由selectWorkerForForwarding选择转发目标,最终通过createForwardedActionResponse构造跨worker请求。可操作建议涉及审计时重点关注action绑定逻辑与转发路径的归一化处理。 综合评分: 85 文章分类: WEB安全,代码审计,漏洞分析,安全开发,应用安全


cover_image

跟我零基础跟完RSC反序列(1)

原创

YMsora YMsora

YMs0ra的安全漫路

2026年4月7日 00:41 浙江

(1)

1.React框架的next-action初步

业务逻辑的跟进

关于next-action这个头,是一种函数身份的定位,也就是一串hax值,react框架构建以来,每个函数会绑定一串hax,作为标识符.

当然我的审计是从next-action的识别及后续开始的,所以我暂时不会在初步构建以及hax加密这块去做工作。

另外,为了加强文档可读性,我会较多换行。那就 START

if (actionId) {
        const forwardedWorker = (0, _actionutils.selectWorkerForForwarding)(actionId, page, serverActionsManifest);
        // If forwardedWorker is truthy, it means there isn't a worker for the action
        // in the current handler, so we forward the request to a worker that has the action.
        if (forwardedWorker) {
            return {
                type: 'done',
                result: await createForwardedActionResponse(req, res, host, forwardedWorker, ctx.renderOpts.basePath)
            };
        }
    }

其中selectWorkerForForwarding这个函数,溯源之后是.d.ts的声明文档,在同目录下的js文件处找到了源function。

function selectWorkerForForwarding(actionId, pageName, serverActionsManifest) {
    var _serverActionsManifest__actionId;
    const workers = (_serverActionsManifest__actionId = serverActionsManifest[process.env.NEXT_RUNTIME === 'edge' ? 'edge' : 'node'][actionId]) == null ? void 0 : _serverActionsManifest__actionId.workers;
    const workerName = normalizeWorkerPageName(pageName);
    // no workers, nothing to forward to
    if (!workers) return;
    // if there is a worker for this page, no need to forward it.
    if (workers[workerName]) {
        return;
    }
    // otherwise, grab the first worker that has a handler for this action id
    return denormalizeWorkerPageName(Object.keys(workers)[0]);
}

这里的serverActionManifest参数类似一张actionid和worker进程的对应表单,下面就是return,其中denormalizeWorkerPagename是返回转发路径的。

也就是说,serverActionsManifest的action匹配的workers值被赋值给workers,然后denormalizeWorkerPageName将所有对应的workers的路径返回。

*/ function denormalizeWorkerPageName(bundlePath) {
    return (0, _apppaths.normalizeAppPath)((0, _removepathprefix.removePathPrefix)(bundlePath, 'app'));
}

接下来就是1返回的createForwardedActionResponse,简化的最终请求就是

const response = await fetch(fetchUrl, {
            method: 'POST',
            body,
            duplex: 'half',
            headers: forwardedHeaders,
            redirect: 'manual',
            next: {
                // @ts-ignore
                internal: 1
            }
        });

body经过strearm之后可以分块读取数据,body是我们的req,headers是扒res的cookie之类的字段送过去

const forwardedHeaders = getForwardedHeaders(req, res);

以上,next-action的前置分析完成,再者就到了action的server接收以及解析。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:YMs0ra的安全漫路 YMsora YMsora《跟我零基础跟完RSC反序列(1)》

评论:0   参与:  0