:如何实现论坛发帖时需要用户通过手机发送验证码到指定手机号码来完成实名认证后才能登录提交?
我有一个论坛网站,需要用户发帖或回帖前先提交手机号码和验证码完成实名认证。实现方法是发帖子前,将网站页面上提供的验证码(8位数字)通过用户自己手机发送到指定手机号码上,网站上的短信猫或手机收到短信后,将数据存到SQL Server数据库指定表中,网站在等待的过程中轮询这张表,轮询到了用户登记手机号和短信验证码,符合时就通过用户的登录请求,并允许发帖或回帖提交,这就是整个过程。我现在想问问有没有这方面的硬件短信猫购买,或者用普通的安卓手机的话,Windows系统下有没有现成的安卓手机短信读取程序。如果没有,我计划自己用C#开发一个实现这个读取手机短信并写入SQL Server指定表的程序,难吗?提供代码给我。

先说整体评估、方案选型,再讲 C# 开发难度,最后给可运行 Demo(附风险、坑点、替代方案)
你的业务逻辑梳理:
用户在论坛页面看到8 位数字验证码 → 用户用自己手机发短信到你的接收号码 → 你的接收端(短信猫 / 安卓手机)收到这条短信 → 程序读取短信,解析手机号 + 8 位验证码,写入 SQL Server → 论坛前端轮询数据库,匹配成功放行发帖。
✅ 本质:短信上行接收(MO),不是我们常用的短信下行(给用户发短信验证码),这点很多人搞反。
一、硬件选型:短信猫(GSM Modem / 4G 短信猫)
1. 能不能买到?
可以买到,淘宝、1688 搜关键词:GSM 短信猫、4G 短信猫、USB 短信猫、工业短信猫
⚠️ 重要提醒:
短信猫里面要插一张国内正常能收短信的手机卡,必须实名,卡不能停机、不能关闭短信功能;很多物联网卡只允许下行,不支持上行接收短信,买卡前一定要确认:支持 MO 上行短信。
合规红线:你这个是接收用户主动发来的短信做论坛验证,不能用来群发垃圾短信,否则卡直接封、设备连带追责。
短信猫的开发方式
C# 通过串口(SerialPort)发 AT 指令 读取短信,是非常成熟的方案,网上资料多。
缺点:4G 模块 AT 指令各家略有差异,EC20 系列文档最多。
二、安卓手机方案(Windows 下读取安卓收到的短信)
有没有现成成品程序?
很少有成熟商用成品刚好适配你这个需求(收到短信自动解析、入库 SQL Server),零散小工具大多只能看短信、导出 csv,没有直接对接 SQL Server、自动解析验证码的。
原理是用 ADB(Android Debug Bridge):Windows 电脑通过 USB 开启安卓调试,adb 命令读取手机短信数据库。
前提条件:
安卓手机开启【开发者选项】+【USB 调试】;
手机插上 USB 连 Windows,授权这台电脑的调试;
手机需要一直插电、亮屏 / 保持后台,手机系统杀后台、省电策略是大坑! 小米 / OPPO/vivo/ 鸿蒙很容易杀掉短信相关、adb 连接断线。
安卓版本限制:Android 12+ 对短信权限收紧;Android 14 限制 adb 读取短信,高版本安卓 adb 直接读短信会权限失败,这个是硬限制!
✅ 适合:备用旧安卓机(Android 9 ~ 11 最稳),不适合 7×24 小时工业稳定运行。
两种 adb 读取短信路线:
adb shell content query 读取 sms 表(简单,但是高版本安卓失效)
安卓端装一个短信转发 APP(比如 SMS Forwarder、Tasker),收到短信后,主动推 HTTP 请求到你 Windows 上的 API
👉 【强烈推荐安卓方案走这个】:手机端 APP 收到短信 → HTTP POST 发给 Windows 本地服务,而不是 Windows 轮询 adb 拉短信!稳定性高非常多,避开 adb 权限和断线问题。
根据上面的分析,因为我的论坛一天应该不超过50个帖子,我倾向于采用安卓手机接收短信,我的手机号只接收短信、不发送短信,详细介绍一下这个方案和能实现POST转发短信到外部网站接口的APP吧。我的论坛服务器上要增加一个接收页面,提供一下这个接收页面的asp格式代码吧,这个页面最好要转发短信的手机APP在POST的信息中提供一个唯一识别码防止别人乱发送信息过来。
整体方案总览(适配你:日帖≤50、只用安卓收短信、只收不发、ASP 接收接口、带密钥防刷)
流程:
备用安卓手机插接收短信的 SIM 卡,只收短信、不发短信;手机常驻通电、关闭省电 / 内存优化。
安卓短信转发 APP:收到短信 → POST JSON 到你论坛服务器上的 ASP 接口页面,POST 包里面带上你自己设置的密钥(唯一识别码,相当于口令)。
ASP 接收页面:
你的论坛发帖页:前端 JS 轮询这张表,匹配「用户手机号 + 8 位验证码 + 未使用 + 未超时」,匹配成功放行发帖,同时标记 IsUsed=1。
优点:并发对你完全够用(一天几十条)、成本低;避开 ADB 各种权限 / 断线坑;密钥防止外网其他人随便 POST 垃圾数据灌库。
风险重申:安卓系统省电策略是最大敌人;优先 Android 9~11,Android13 + 很多短信转发 APP 会被后台杀掉。
一、推荐安卓短信转发 APP(支持自定义 POST Webhook、带自定义头部 / 自定义参数密钥)
下面 3 个是圈内最常用、免费可用、支持自定义 POST JSON、适合你场景,按推荐顺序:
1. 短信转发器(SMS Forwarder,国产,优先推荐)
{
"token": "ABC123456XYZ789",
"from": "${from}",
"content": "${body}",
"receive_time": "${time}"
}
ABC123456XYZ789 是你自己生成的密钥(唯一识别码),自己改成一串长随机字符串,不要泄露;${from} = 发短信过来的用户手机号; ${body} = 短信原文;
目标 URL:https://你的域名/sms_receive.asp(就是下面给你的 ASP 页面地址)
2. Tasker(进阶,免费版够用)
功能极强,配合短信接收插件,可以构造 HTTP POST;配置复杂一点,适合会折腾的,不推荐新手。
3. AutoSMS / SMS Gateway(国外)
不推荐,国内下载麻烦、中文短信偶尔编码乱码。
❌ 避坑:不要用那种只能推微信 / 邮箱的转发工具,必须明确支持 HTTP POST JSON Webhook。
补充:手机 SIM 卡只收不发,在 APP 里不用配置任何发送规则,只配置【收到短信→POST】一条规则即可。
二、SQL Server 表(沿用,增加说明,如果你还没建)
CREATE TABLE SmsInbound(
Id INT IDENTITY(1,1) PRIMARY KEY,
SenderMobile VARCHAR(20) NOT NULL, -- 用户手机号(发验证码给你的号码)
SmsContent NVARCHAR(500) NOT NULL, -- 短信原文
VerifyCode VARCHAR(10) NULL, -- 提取出的6位验证码
ReceiveTime DATETIME DEFAULT GETDATE(),
IsUsed BIT DEFAULT 0, -- 是否已经验证消费
TokenCheck NVARCHAR(100) NULL -- 记录本次提交的token,方便日志排查(可选)
)
GO
-- 建议加索引,论坛轮询查询更快
CREATE INDEX IX_SmsInbound_Mobile_Code ON SmsInbound(SenderMobile,VerifyCode,IsUsed)
三、ASP(经典 ASP,VBScript)接收页面 sms_receive.asp 【核心代码】
适配:IIS + ASP + SQL Server(ADODB);支持接收 application/json 的 POST;
逻辑顺序:
读取 POST 原始 JSON
解析 JSON、校验 token 密钥,不对直接返回 fail,不碰数据库
提取 from(手机号)、content(短信内容)
正则提取里面 8 位数字验证码
写入数据库
返回 JSON 结果给短信转发 APP
⚠️ 经典 ASP 原生没有 JSON 解析,我这里用一个轻量 JSON 类(内嵌在页面,不需要额外组件),IIS 默认环境就能跑。
⚠️ 重要:修改两处:Const ValidToken(你的密钥)、数据库连接串。
<%
Option Explicit
Response.Buffer = True
Response.ContentType = "application/json;charset=utf-8"
Response.Charset = "utf-8"
' ========== 配置项,这里改成你自己的 ==========
Const ValidToken = "ABC123456XYZ789" ' 和短信转发APP里面的token保持一致!
Const ConnStr = "Provider=SQLOLEDB;Data Source=你的SQL地址;Initial Catalog=你的数据库名;User ID=sa;Password=你的数据库密码;"
' =============================================
Dim strPost, json, token, fromMobile, smsContent, verifyCode
Dim reg, matches, conn, cmd, sql
' 读取POST原始数据
strPost = Request.BinaryRead(Request.TotalBytes)
strPost = BytesToStr(strPost, "UTF-8")
If Trim(strPost) = "" Then
Call ReturnJson("fail", "empty post")
Response.End
End If
' 解析JSON
Set json = New JSON
Call json.Load(strPost)
token = Trim(json.GetValue("token"))
fromMobile = Trim(json.GetValue("from"))
smsContent = Trim(json.GetValue("content"))
' 校验密钥(防别人乱刷接口)
If token <> ValidToken Then
Call ReturnJson("fail", "token invalid")
Response.End
End If
' 简单校验手机号、短信内容不为空
If fromMobile = "" Or smsContent = "" Then
Call ReturnJson("fail", "param empty")
Response.End
End If
' 正则提取8位数字验证码
verifyCode = ""
Set reg = New RegExp
reg.Pattern = "\d{8}"
reg.Global = False
reg.IgnoreCase = True
Set matches = reg.Execute(smsContent)
If matches.Count > 0 Then
verifyCode = matches(0).Value
End If
' 写入SQL Server
On Error Resume Next
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open ConnStr
If Err.Number <> 0 Then
Call ReturnJson("fail", "db connect error:" & Err.Description)
Response.End
End If
sql = "INSERT INTO SmsInbound(SenderMobile,SmsContent,VerifyCode,TokenCheck) VALUES(?,?,?,?)"
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.CommandType = 1 ' adCmdText
cmd.Parameters.Append cmd.CreateParameter("@p1",200,1,20,fromMobile)
cmd.Parameters.Append cmd.CreateParameter("@p2",203,1,500,smsContent)
cmd.Parameters.Append cmd.CreateParameter("@p3",200,1,10,verifyCode)
cmd.Parameters.Append cmd.CreateParameter("@p4",200,1,100,token)
cmd.Execute
If Err.Number <> 0 Then
Call ReturnJson("fail", "insert error:" & Err.Description)
Else
Call ReturnJson("ok", "success")
End If
conn.Close
Set cmd = Nothing
Set conn = Nothing
Set reg = Nothing
Set json = Nothing
Response.End
' ========== 函数区 ==========
' 返回JSON
Sub ReturnJson(status, msg)
Response.Write "{""status"":""" & status & """,""msg"":""" & Server.HTMLEncode(msg) & """}"
End Sub
' 二进制转UTF8字符串
Function BytesToStr(bytes, charset)
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Mode = 3
objStream.Open
objStream.Write bytes
objStream.Position = 0
objStream.Type = 2
objStream.Charset = charset
BytesToStr = objStream.ReadText
objStream.Close
Set objStream = Nothing
End Function
' 简易JSON解析类(经典ASP内嵌,只适合解析单层简单JSON,刚好满足你的需求)
Class JSON
Private m_Data
Public Sub Load(jsonStr)
Dim reg, mc, key, val, tmp
Set reg = New RegExp
reg.Pattern = """([^""]+)""\s*:\s*""?([^,""}]*)""?"
reg.Global = True
Set mc = reg.Execute(jsonStr)
Set m_Data = CreateObject("Scripting.Dictionary")
Dim i
For i = 0 To mc.Count - 1
key = mc(i).SubMatches(0)
val = mc(i).SubMatches(1)
m_Data(key) = val
Next
Set reg = Nothing
End Sub
Public Function GetValue(key)
If m_Data.Exists(key) Then
GetValue = m_Data(key)
Else
GetValue = ""
End If
End Function
End Class
%>
页面部署和 IIS 注意事项
保存为 sms_receive.asp 放到你的网站目录;
IIS 里面 ASP 开启父路径、开启 ADODB 组件(默认一般是开的);
给网站目录 IIS 用户写入权限(数据库权限重点:SQL 账号要有表 INSERT 权限);
优先 HTTPS,HTTP 也能跑,但是部分短信转发 APP 不支持明文 HTTP,推荐配置 SSL;
测试方法:你可以用 Postman 模拟 POST,Body 选 JSON:
{
"token": "ABC123456XYZ789",
"from": "13800138000",
"content": "886677 验证"
}
token 不对会直接返回 token invalid,达到防乱提交的目的。
四、配套:论坛前端轮询逻辑简要说明(你现有发帖页面改造)
用户在发帖页,页面上展示 8 位验证码,提示:请用本机手机号发送这串数字到【你的接收手机号】前端 JS 逻辑:
用户点提交之后,前端开启轮询(2~3 秒一次,不要太快);
轮询后台一个查询 ASP 页面(你自己写一个简单查询页,同样建议加 session 校验,不要裸暴露查询接口);
查询条件:SenderMobile=用户手机号 AND VerifyCode=页面展示的6位码 AND IsUsed=0
查询命中:立刻执行 UPDATE 把 IsUsed=1,停止轮询,放行帖子入库;
超时:比如 5 分钟没有匹配,提示验证失败;
建议:查询接口不要直接暴露给任何人,最好绑定当前用户 Session,防止别人扫库。
五、安卓手机侧额外优化 & 避坑清单(非常关键)
手机:优先找 Android 9 /10 /11 的旧备用机;Android12+ 短信权限、后台限制很严,转发容易失效;
SIM 卡:实名、关闭彩铃 / 增值业务,确认可以正常接收上行短信;不要物联网卡(很多物联网卡不接收 MO 上行);
网络:手机连家里稳定 WiFi,优先固定 WiFi,不要流量;WiFi 掉线 APP 会重试 POST;
省电(重中之重):
关闭电池优化 → 对【短信转发器】关闭;
关闭应用自动休眠、后台限制;
锁定 APP 在最近任务列表;
手机一直插充电器;
关闭系统自动清理内存。
APP 里面开启【请求失败重试】,网络抖动的时候自动重试推送到你的 ASP 接口。
六、安全补充建议
Token 密钥尽量长、随机,不要放在网页里,只在安卓 APP 和 ASP 后端里面写死;
这个 ASP 接口只用来收短信,不要对外公开给普通用户访问;
可以再加一层:在 ASP 里面加 IP 白名单,只允许你安卓手机的公网 IPPOST 进来(进阶);
定时脚本清理 SmsInbound 超过比如 24 小时的旧记录,防止表越来越大。
如果你需要,我可以再给你配套的:
sms_query.asp —— 前端轮询查询接口(带 Session 校验,防止别人扫接口)
发帖页嵌入的前端 JS 轮询代码
前置约定:
和前面 sms_receive.asp 共用同一张 SmsInbound 表、同一个 SQL 连接串
逻辑:用户登录论坛后,Session 里保存用户手机号 Session("UserMobile")
验证成功后,自动标记 IsUsed=1,防止验证码重复复用
超时控制:5 分钟有效期(ReceiveTime >= DATEADD (minute,-5,GETDATE ()))
一、sms_query.asp 【轮询查询接口】
<%
Option Explicit
Response.Buffer = True
Response.ContentType = "application/json;charset=utf-8"
Response.Charset = "utf-8"
'===== 配置区,和 sms_receive.asp 保持一致 =====
Const ConnStr = "Provider=SQLOLEDB;Data Source=你的SQL地址;Initial Catalog=你的数据库名;User ID=sa;Password=你的数据库密码;"
Const ValidMinute = 5 '验证码有效时长(分钟)
'===============================================
Dim UserMobile, CheckCode, conn, rs, sql
UserMobile = Trim(Session("UserMobile"))
CheckCode = Trim(Request.QueryString("code"))
' 1. 校验会话:未登录/没有手机号直接拒绝
If UserMobile = "" Then
Call ReturnJson("fail", "no_session", "用户会话失效,请刷新页面")
Response.End
End If
' 2. 校验传入的6位验证码
If CheckCode = "" Or Len(CheckCode)<>8 Or Not IsNumeric(CheckCode) Then
Call ReturnJson("fail", "param_error", "验证码格式错误")
Response.End
End If
On Error Resume Next
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open ConnStr
If Err.Number<>0 Then
Call ReturnJson("fail","db_error","数据库连接失败:" & Err.Description)
Response.End
End If
' 查询:手机号匹配、验证码匹配、未使用、5分钟内
sql = "SELECT Id FROM SmsInbound WHERE SenderMobile=? AND VerifyCode=? AND IsUsed=0 AND ReceiveTime >= DATEADD(minute,-" & ValidMinute & ",GETDATE())"
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.CommandType = 1
cmd.Parameters.Append cmd.CreateParameter("@p1",200,1,20,UserMobile)
cmd.Parameters.Append cmd.CreateParameter("@p2",200,1,10,CheckCode)
Set rs = cmd.Execute
If Not rs.EOF Then
'找到有效记录 → 标记已使用
Dim updateSql
updateSql = "UPDATE SmsInbound SET IsUsed=1 WHERE Id=?"
Dim cmd2
Set cmd2 = Server.CreateObject("ADODB.Command")
cmd2.ActiveConnection = conn
cmd2.CommandText = updateSql
cmd2.CommandType = 1
cmd2.Parameters.Append cmd2.CreateParameter("@pid",3,1,4,rs("Id"))
cmd2.Execute
Set cmd2=Nothing
'验证成功
Call ReturnJson("ok","passed","验证通过,可以提交帖子")
Else
'还没收到短信或者已过期/已使用
Call ReturnJson("wait","waiting","暂未收到匹配短信,请发送后等待")
End If
rs.Close
conn.Close
Set rs=Nothing
Set cmd=Nothing
Set conn=Nothing
Response.End
Sub ReturnJson(status,code,msg)
Response.Write "{""status"":"""&status&""",""code"":"""&code&""",""msg"":""" & Server.HTMLEncode(msg) & """}"
End Sub
%>
使用说明
论坛登录逻辑里,登录成功必须赋值:
Session("UserMobile") = "用户的手机号"
这个 Session 是防护核心:别人拿验证码也不能随便查别人的记录。
前端请求示例(GET):
https://你的域名/sms_query.asp?code=12345678
返回值三种状态:
{"status":"ok"}:验证通过,停止轮询,放行发帖
{"status":"wait"}:继续等待,继续轮询
{"status":"fail"}:会话失效 / 参数错误,停止轮询,提示用户
二、发帖页面:前端 JS 轮询代码(嵌入你的发帖 ASP 页面)
假设:页面上你预先生成了 8 位验证码,存在变量 verifyCode,同时展示给用户,提示【请用你的手机号发送 12345678 到接收号码 138XXXXXXX】
<script type="text/javascript">
var verifyCode = "<%= 这里输出你后端生成的6位数字验证码 %>";
var pollingTimer = null;
var isVerified = false;
var pollingUrl = "/sms_query.asp?code=" + verifyCode;
// 开始轮询
function startSmsPolling(){
if(isVerified) return;
console.log("开始轮询验证码:" + verifyCode);
pollingTimer = setInterval(checkSmsCode, 2500); // 2.5秒轮询一次,压力很小
}
// 停止轮询
function stopSmsPolling(){
clearInterval(pollingTimer);
}
function checkSmsCode(){
if(isVerified){
stopSmsPolling();
return;
}
var xhr = new XMLHttpRequest();
xhr.open("GET", pollingUrl, true);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
try{
var res = JSON.parse(xhr.responseText);
if(res.status === "ok"){
isVerified = true;
stopSmsPolling();
alert("短信验证成功!即将提交帖子");
// ========= 验证成功,自动触发表单提交 =========
document.getElementById("postform").submit();
}else if(res.status === "fail"){
stopSmsPolling();
alert("验证失败:" + res.msg);
}
// status=wait 不做提示,静默继续轮询
}catch(e){
// json解析错误,忽略,下一轮继续
}
}
};
xhr.send();
}
//===== 页面加载完毕自动启动轮询 =====
window.onload = function(){
startSmsPolling();
};
//===== 用户点【取消】按钮停止轮询 =====
function cancelVerify(){
stopSmsPolling();
isVerified = true;
alert("已取消短信验证");
}
</script>
<!-- 你的发帖表单示例,表单id必须是 postform -->
<form id="postform" action="savepost.asp" method="post">
<p>请发送验证码 <strong style="font-size:22px;color:red;"><%= 后端输出6位验证码 %></strong> 到接收手机号:138XXXXXXX</p>
<textarea name="content"></textarea>
<br>
<input type="submit" value="提交帖子" disabled />
<button type="button" onclick="cancelVerify()">取消验证</button>
</form>
重要细节说明
你原来的逻辑:后端 ASP 先随机生成 8 位数字验证码,展示在页面,这个生成逻辑你自己写在发帖页。
我上面示例里表单提交按钮我写了 disabled,你可以改成:验证成功之后 JS 再把按钮启用,而不是自动 submit,看你喜好,我给你备选版本:
// 验证成功时,启用按钮,而不是自动提交
document.querySelector('input[type="submit"]').disabled = false;
alert("短信验证成功,现在可以点提交帖子");
轮询间隔 2500ms,对你日 50 帖的负载完全没问题,不会打数据库。
三、整套流程串联回顾(方便你核对)
用户打开发帖页 → 论坛 ASP 生成 8 位验证码,存入页面,同时 Session("UserMobile") 是该用户手机号
用户拿自己手机,发短信:12345678 → 你的安卓接收卡号码
安卓【短信转发器 APP】收到短信,POST JSON(带 token)→ sms_receive.asp
sms_receive.asp 校验 token,提取手机号 + 8 位码,写入 SmsInbound 表
前端 JS 持续轮询 sms_query.asp,带上 8 位验证码
sms_query.asp 拿 Session 里的手机号 + url 里的验证码去查表
查到有效记录 → UPDATE 设置 IsUsed=1,返回 ok,JS 放行发帖
四、额外安全小补充(可选)
如果你想再加固 sms_query.asp,可以再加一个超时:前端最多轮询 5 分钟,JS 侧计时,时间到自动停止轮询,避免页面一直后台请求:
var pollingStart = Date.now();
var maxPollMs = 5 * 60 * 1000; //5分钟
function checkSmsCode(){
if(Date.now() - pollingStart > maxPollMs){
stopSmsPolling();
alert("验证超时,请刷新页面重新获取验证码");
return;
}
// 剩下原有xhr代码
}
下面是一段随机生成 8 位验证码的 ASP 代码(生成验证码同时可选存入 Session,防止篡改页面上的验证码)。
随机 8 位验证码生成 ASP 代码
作用:打开发帖页面时,后端生成 8 位数字验证码,同时存到 Session 里面好处:防止用户在浏览器 F12 修改页面上显示的验证码数字去欺骗验证;页面展示的验证码以 Session 里的为准
配套和前面整套体系兼容:sms_query.asp、sms_receive.asp、前端 JS
新建或者直接嵌入你的发帖页面(比如 post.asp)顶部:
<%
Option Explicit
' 验证码配置
Const CodeLen = 8
Const CodeSessionKey = "SmsPostVerifyCode"
Dim verifyCode
' 如果当前会话还没有验证码,则生成;避免刷新页面反复换新码(可选)
If Session(CodeSessionKey) = "" Then
verifyCode = Generate8Code()
Session(CodeSessionKey) = verifyCode
Else
verifyCode = Session(CodeSessionKey)
End If
' 生成8位纯数字
Function Generate8Code()
Dim rndNum, i, s
Randomize Timer
s = ""
For i=1 To CodeLen
rndNum = Int(Rnd() * 10)
s = s & CStr(rndNum)
Next
Generate6Code = s
End Function
' 【可选接口】重置验证码:用户点“换一个验证码”按钮时调用这个
' 调用示例:post.asp?resetcode=1
If Request.QueryString("resetcode")="1" Then
Session(CodeSessionKey) = Generate8Code()
Response.Redirect "post.asp"
Response.End
End If
%>
在页面 HTML 里输出验证码给用户看
<p>请发送验证码:<strong style="font-size:24px;color:#c00;"><%= verifyCode %></strong>
<br>发送到接收短信号码:<b>138XXXXXXXX</b></p>
前端 JS 里面取值也要改成从后端输出 Session 里的验证码(防篡改)
原来 JS 那句:
var verifyCode = "<%= 这里输出你后端生成的8位数字验证码 %>";
改成:
var verifyCode = "<%= Server.HTMLEncode(verifyCode) %>";
var pollingUrl = "/sms_query.asp?code=" + verifyCode;
✅ 重要改造:修改 sms_query.asp,增加校验 Session 内验证码
原来的 sms_query.asp 只校验 Session("UserMobile"),现在再加一层:URL 传过来的 code 必须等于 Session 里存的验证码防止别人随便遍历 8 位数字爆破接口!
找到 sms_query.asp 里面这一段:
UserMobile = Trim(Session("UserMobile"))
CheckCode = Trim(Request.QueryString("code"))
替换成下面新版:
UserMobile = Trim(Session("UserMobile"))
CheckCode = Trim(Request.QueryString("code"))
Dim SessionCode : SessionCode = Trim(Session("SmsPostVerifyCode"))
' 1. 校验会话:未登录/没有手机号直接拒绝
If UserMobile = "" Then
Call ReturnJson("fail", "no_session", "用户会话失效,请刷新页面")
Response.End
End If
' 新增:校验前端传过来的code 和服务端Session里保存的验证码一致
If SessionCode = "" Or CheckCode <> SessionCode Then
Call ReturnJson("fail", "code_mismatch", "验证码不匹配,请刷新页面")
Response.End
End If
' 2. 校验传入的6位验证码
If CheckCode = "" Or Len(CheckCode)<>8 Or Not IsNumeric(CheckCode) Then
Call ReturnJson("fail", "param_error", "验证码格式错误")
Response.End
End If
逻辑说明:
用户打开发帖页 → 服务端生成 12345678 存入 Session ("SmsPostVerifyCode")
前端只能拿到这个值去轮询;就算改浏览器地址上 ?code=87654321,服务端对比 Session 不一致,直接拒绝。
✅ 验证成功之后,务必清空验证码 Session(防止重复提交二次使用)
找到 sms_query.asp 里面验证成功、执行 UPDATE 之后这一行:
Call ReturnJson("ok","passed","验证通过,可以提交帖子")
在它前面增加一句清空 Session:
Session("SmsPostVerifyCode") = "" '验证通过,销毁本次验证码,不能再用
Call ReturnJson("ok","passed","验证通过,可以提交帖子")
✅ 发帖保存成功页面 savepost.asp 补充(可选)
帖子入库成功之后,也建议清理验证码 Session,防止残留:
Session("SmsPostVerifyCode") = ""
✅ 增加【换一个验证码】按钮(放在发帖页面)
<a href="post.asp?resetcode=1">换一组验证码</a>
点击之后,旧验证码失效,服务端生成新 8 位数字。
📌 整套现在安全链路汇总(闭环)
访问发帖页 post.asp → 生成 8 位验证码存入 Session ("SmsPostVerifyCode")
Session 同时保存:Session("UserMobile") 用户手机号
用户发短信(Session 里那串 8 位数字)到你的安卓接收卡
短信转发 APP POST 带 token → sms_receive.asp 入库 SmsInbound
JS 轮询 sms_query.asp?code=xxxxxx
sms_query.asp 三重校验:
校验通过:标记 IsUsed=1,清空验证码 Session,返回 ok 放行发帖
自动清理短信记录表页面:sms_clean.asp
功能说明:
清理 SmsInbound 表中超过指定小时的旧短信记录(默认 24 小时,你可以自行修改)
可以设置一个访问密钥,防止任何人随便访问这个清理页面删数据
适合在 Windows 服务器计划任务(任务计划程序)定时调用,比如每 4 小时 GET 请求一次这个页面
执行后返回清理结果,方便看日志
<%
Option Explicit
Response.Buffer = True
Response.ContentType = "text/plain;charset=utf-8"
Response.Charset = "utf-8"
' ========== 配置区 ==========
Const ConnStr = "Provider=SQLOLEDB;Data Source=你的SQL地址;Initial Catalog=你的数据库名;User ID=sa;Password=你的数据库密码;"
Const CleanToken = "Clean@2026Sms" ' 清理接口访问密钥,自己改成复杂串
Const ExpireHour = 24 ' 删除多久之前的数据,单位小时
' ============================
Dim Token, conn, cmd, sql, AffectRows
Token = Trim(Request.QueryString("token"))
' 密钥校验
If Token <> CleanToken Then
Response.Write "ERROR: token invalid"
Response.End
End If
On Error Resume Next
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open ConnStr
If Err.Number <> 0 Then
Response.Write "DB CONNECT ERROR:" & Err.Description
Response.End
End If
' 删除超时记录
sql = "DELETE FROM SmsInbound WHERE ReceiveTime < DATEADD(hour,-" & ExpireHour & ",GETDATE())"
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.CommandType = 1
cmd.Execute AffectRows
If Err.Number <> 0 Then
Response.Write "DELETE ERROR:" & Err.Description
Else
Response.Write "OK. Deleted rows: " & CStr(AffectRows)
End If
conn.Close
Set cmd = Nothing
Set conn = Nothing
%>
使用方式
访问地址格式(必须带上正确 token):
https://你的域名/sms_clean.asp?token=Clean@2026Sms
返回示例:
OK. Deleted rows: 12 → 成功,删掉 12 条旧记录
OK. Deleted rows: 0 → 没有过期数据
ERROR: token invalid → 密钥不对拒绝执行
Windows 服务器计划任务配置(IIS 服务器本机)
服务器打开【任务计划程序】→ 创建基本任务
触发器:按需求,例如每 4 小时一次
操作:启动程序
https://你的域名/sms_clean.asp?token=Clean@2026Sms
如果服务器没有 curl,可以用 wget,或者写一个简单 vbs 脚本调用 MSXML2.XMLHTTP 去 GET 这个链接。
备选:vbs 脚本版本(适合服务器没有 curl)
保存为 sms_clean.vbs,计划任务直接运行这个 vbs:
Dim http, url
url = "https://你的域名/sms_clean.asp?token=Clean@2026Sms"
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", url, False
http.Send
WScript.Echo http.ResponseText
整套全部文件清单汇总(方便你归档)
sms_receive.asp — 安卓短信转发 APP POST 接收、入库、带 token 防刷
sms_query.asp — 前端轮询查询、Session 三重校验、验证通过标记已使用
post.asp — 发帖主页面(验证码生成 + 展示 + JS 轮询)
savepost.asp — 帖子保存页(记得清空验证码 Session)
sms_clean.asp — 定时清理过期短信数据
额外一个小建议
你现在整套链路:用户发帖页生成验证码 → 用户发短信 → 安卓转发APP POST → sms_receive.asp入库 → js轮询sms_query.asp校验
该文章在 2026/10/31 14:44:54 编辑过