当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

传奇NPC脚本中@@InPutString非法字符过滤实战:从输入拦截到数据落盘

热度:
一、引擎内置过滤机制与触发链路

@@InPutStringX弹框输入后,客户端把字符串发回服务端,引擎先做第一层校验:命中M2过滤列表→直接跳转[@IsInFilterList](Hero端)或[@MsgFilter](3K端),不写入S变量、不执行后续脚本。这一层是硬编码在引擎里的,脚本层面无法绕过,但过滤列表的内容完全由服务端维护。

过滤列表位置:M2控制器→查看→列表信息→其他设置→过滤字符(部分版本存为GuildRankNameFilter.txt或FilterChar.txt)。每行一个词条,支持纯文本匹配。玩家输入包含任意词条即触发跳转。

二、脚本层二次校验:长度、字符集、格式

内置过滤只管"有没有命中词条",不管长度超限、纯数字、特殊符号组合等问题。实际脚本必须在回调段里加#if条件判断:

[@CallInPutString10]
if

EQUALS10
act

MESSAGEBOX输入不能为空
GOTO@main
elsesay

if

LARGE$STRLEN(S10)20
act

MESSAGEBOX输入长度不能超过20个字符
GOTO@main
elsesay

;继续正常逻辑
act

SENDMSG6输入内容:S10

说明:部分引擎支持$STRLEN()函数取字符串长度,不支持的用自定义计数或限制输入源(客户端输入框本身有字节上限)。

三、逐字符扫描检测特殊符号

对于需要严格限制字符集的场景(如行会名只允许中文+字母+数字),用循环或多次CHECKCONTAINS判断:

if

CHECKCONTAINSS10~
act

MESSAGEBOX不能包含~符号
GOTO@main
elsesay

if

CHECKCONTAINSS10`
act

MESSAGEBOX不能包含`符号
GOTO@main
elsesay

if

CHECKCONTAINSS10|
act

MESSAGEBOX不能包含|符号
GOTO@main
elsesay

if

CHECKCONTAINSS10<
act

MESSAGEBOX不能包含<符号
GOTO@main
elsesay

if

CHECKCONTAINSS10>
act

MESSAGEBOX不能包含>符号
GOTO@main
elsesay

if

CHECKCONTAINSS10&
act

MESSAGEBOX不能包含&符号
GOTO@main
elsesay

;全部通过才执行
act

GOTO@process

需要屏蔽的字符清单(按危害程度排序):
•|:部分版本脚本解析器把|当命令分隔符,注入后可执行额外指令

•<>:脚本标签语法符号,输入含<可能被误解析为标签跳转

•~:变量展开符号,某些引擎里~S10会展开为全局变量

•&:条件连接符,可能干扰#if解析

•'":SQL注入场景(如果后端用文本数据库且未转义)

•\r\n:换行注入,破坏脚本块结构

四、数字型输入的双重保险

即使弹的是@@InPutString,玩家也可能输入纯数字。如果需要数字,回调段里用EQUAL/NOTEQUAL+范围判断:

[@CallInPutString11]
if

EQUALS110
act

MESSAGEBOX不能为0
GOTO@main
elsesay

if

SMALLN111
act

MESSAGEBOX不能小于1
GOTO@main
elsesay

if

LARGEN119999
act

MESSAGEBOX不能超过9999
GOTO@main
elsesay

act

;S11已确认为合法数字字符串,N11为对应数值
SENDMSG6确认数值:N11

注意:@@InPutString的结果在S变量里,但引擎同时会尝试解析为数字存入同名N变量(如S11→N11)。如果输入含非数字字符,N11为0,可以用这个特性做"纯数字校验"——N11==0且S11不为"0"说明含字母。

五、数据库落盘前的转义处理

输入最终要写入文本文件或数据库时,必须做转义:

1.写文本文件(SAVEVAR):
变量内容含换行符会破坏文件格式。在写入前用REPLACE函数清除或替换危险字符:
CALCVARGLOBALZ1=$REPLACE(S10"|""")
CALCVARGLOBALZ1=$REPLACE(Z1"<""")
CALCVARGLOBALZ1=$REPLACE(Z1">""")
SAVEVARGLOBALZ1..\QuestDiary\数据文件\InputLog.txt

2.写DBC2000/Access:
通过脚本命令写入数据库的记录,字段长度限制要在脚本层提前拦截。比如HeroDB的Guild表Name字段varchar(20),脚本里用$STRLEN限制在20字符内,超长截断或拒绝。

六、行会名/角色名注册完整过滤示例

[@CallInPutString5]
;第一层:空值
if

EQUALS5
act

MESSAGEBOX行会名不能为空
GOTO@main
elsesay

;第二层:长度
if

LARGE$STRLEN(S5)16
act

MESSAGEBOX行会名最多16个字符
GOTO@main
elsesay

;第三层:非法字符
if

CHECKCONTAINSS5~
act

MESSAGEBOX不能包含~符号
GOTO@main
elsesay

if

CHECKCONTAINSS5<
act

MESSAGEBOX不能包含<符号
GOTO@main
elsesay

if

CHECKCONTAINSS5>
act

MESSAGEBOX不能包含>符号
GOTO@main
elsesay

if

CHECKCONTAINSS5|
act

MESSAGEBOX不能包含|符号
GOTO@main
elsesay

;第四层:重复检查
if

CHECKTEXTLIST..\QuestDiary\Guild\GuildNames.txtS5
act

MESSAGEBOX该行会名已被注册
GOTO@main
elsesay

;第五层:引擎内置过滤(自动跳@IsInFilterList,此处不用写)
;全部通过
act

ADDTEXTLIST..\QuestDiary\Guild\GuildNames.txtS5
SENDMSG6行会名[S5]注册成功

[@IsInFilterList]
act

MESSAGEBOX行会名含非法词汇,请重新输入
GOTO@main

七、M2过滤列表维护规范

过滤列表不是越长越好,维护原则:
•按功能分区:行会名过滤、聊天过滤、任务输入过滤分开建表(不同版本支持多个过滤列表文件)

•定期清理:过时的敏感词删掉,避免误拦正常输入

•测试流程:每次加新词条后,用测试号走一遍完整输入流程,确认不误伤

•备份:过滤列表文件改前复制一份.bak,改崩了能回滚

八、多引擎差异汇总

项目Hero引擎3K引擎GOM/GEE

回调段名[@CallInPutStringX][@InPutStringX][@InPutStringX]

过滤跳转段[@IsInFilterList][@MsgFilter][@MsgFilter]

过滤列表位置M2→列表信息→其他设置同左同左

变量存储SX+NXSX+NXSX+NX

CHECKCONTAINS支持支持支持

$STRLEN部分版本支持部分版本支持商业版支持

最大输入长度客户端限制约60字节同左同左

九、调试与日志

输入异常时排查步骤:
1.确认是否触发了[@IsInFilterList]→说明命中引擎过滤列表,去M2列表里查对应词条
2.没触发过滤但后续逻辑异常→在回调段第一行加SENDMSG6调试:S10,看实际写入内容
3.变量读出来是空的→检查回调段名是否拼对(Hero必须带Call)
4.中文变乱码→脚本文件存成UTF-8了,改ANSI
5.特殊符号没被拦住→CHECKCONTAINS的字符可能被引擎吃掉了,换成十六进制比较或升级引擎版本

十、完整防御纵深总结

玩家按键→客户端输入框(长度限制)→@@InPutStringX发包→引擎层过滤列表匹配(@IsInFilterList拦截)→写入S变量→回调段脚本校验(空值/长度/字符集/格式/重复)→转义处理→落盘(文本/DB)。五层防线,任意一层漏了还有下一层兜底。脚本层校验永远不能省——引擎过滤列表只管"有没有这个词",不管业务逻辑合不合法。
[顶部]