ASP.NET 2.0 电商网站如何选择支付网关和 HTTPS?
明确结论
电商网站应全站启用 HTTPS,不能为了节省主机费用而继续使用纯 HTTP。即使支付页面由第三方支付网关托管,商品页、登录页、购物车、结账入口和支付结果通知地址也都应使用 HTTPS。
支付方式应优先选择支付服务商提供的 Hosted Checkout(托管收银台)或 Tokenization(令牌化)方案,让银行卡号、CVV 等敏感信息直接提交给支付服务商。ASP.NET 2.0 应用不应自行接收、保存或记录完整的银行卡数据。
ASP.NET 2.0 已经非常陈旧,不适合用来新建支付系统。正式上线前,应优先升级到仍受支持的 .NET 平台。如果遗留系统暂时无法升级,至少要确认操作系统、IIS 和运行时支持支付服务商要求的 TLS 版本和加密套件。
为什么必须使用 HTTPS
HTTPS 不只是让浏览器显示一个安全标志,它还能解决以下实际问题:
- 加密浏览器与服务器之间传输的登录信息、地址、订单和支付状态。
- 防止页面在传输过程中被篡改,例如结账按钮被替换为攻击者的支付链接。
- 保护 Cookie 和 Session,降低会话被窃取的风险。
- 满足现代浏览器、支付接口和第三方 SDK 的基本安全要求。
- 避免用户结账时看到“不安全”提示,进而影响信任和转化率。
如果银行卡信息会直接提交到自己的网站,没有 HTTPS 就不应上线。即使银行卡表单由第三方托管,HTTP 页面本身仍可能遭到篡改,因此不能把第三方收银台当成不启用 HTTPS 的理由。
HTTPS 只能保护数据传输,无法独自保证整个支付流程的安全。应用仍要妥善处理身份验证、订单金额校验、回调验签、权限控制、日志脱敏和服务器安全更新。
如何选择支付网关
没有适合所有项目的“最佳网关”。选择时要考虑客户所在国家、结算币种、交易量和团队的开发能力,重点比较以下内容:
- 是否支持目标地区使用的 credit card、debit card 和所需卡组织。
- 是否提供 Hosted Checkout、Tokenization,或符合 PCI DSS 要求的前端组件。
- 是否提供 ASP.NET 可以调用的标准 REST API,或者兼容当前运行环境的 SDK。
- 交易费、退款费、拒付费、跨境费、月租费和最低消费。
- 结算周期、支持的币种,以及资金是否直接结算到客户的商户账户。
- 是否支持退款、部分退款、重复付款保护和 3-D Secure。
- Webhook 是否带有签名,是否提供测试环境和完整文档。
- 服务商是否接受客户所属行业,开户审核需要多长时间。
对于 ASP.NET 2.0 项目,可以按以下顺序选择:
- 首选:跳转到支付服务商的托管收银台。
- 次选:使用支付服务商托管的银行卡输入组件,服务器只接收 token。
- 不建议:将银行卡号直接提交到自己的 ASP.NET 应用。
- 应避免:自行保存银行卡号或 CVV。
托管收银台通常开发成本最低,也能大幅缩小 PCI DSS 的合规范围,但商户仍需承担自身的安全和合规责任。具体要求应向支付服务商、收单机构或合规顾问确认。
推荐的支付流程
较为稳妥的支付流程如下:
- 用户在网站创建订单。
- 服务器根据数据库中的商品价格重新计算金额,不接受浏览器提交的总价作为依据。
- 服务器调用支付网关创建支付会话。
- 用户跳转到支付服务商的 HTTPS 收银台。
- 支付完成后,用户返回网站的结果页面。
- 支付服务商另行向网站的 Webhook 地址发送通知。
- 网站验证通知签名,再通过支付网关 API 核实交易状态、金额、币种和订单号。
- 验证通过后,以幂等方式将订单更新为已支付。
不能仅凭用户返回页面中的 success=true 确认订单。返回地址由用户的浏览器访问,其中的参数可能被伪造。最终支付状态应以通过验签和服务器核验的支付通知为准。
ASP.NET 示例结构
不同支付网关使用的字段、签名算法和接口地址各不相同。下面的代码只演示安全的处理结构,不能代替具体服务商的官方 SDK 或文档。
protected void PayButton_Click(object sender, EventArgs e)
{
int orderId = GetValidatedOrderId();
Order order = OrderRepository.GetPendingOrder(orderId);
// 金额必须从服务器端订单数据计算,不能使用页面提交的金额。
decimal amount = OrderCalculator.CalculateTotal(order);
PaymentSessionRequest request = new PaymentSessionRequest();
request.OrderReference = order.Id.ToString();
request.Amount = amount;
request.Currency = "GBP";
request.ReturnUrl = "https://shop.example.com/payment/return.aspx";
request.WebhookUrl = "https://shop.example.com/payment/webhook.aspx";
PaymentSession session = PaymentGateway.CreateSession(request);
// 只允许跳转到配置中认可的支付服务商域名。
ValidatePaymentUrl(session.CheckoutUrl);
Response.Redirect(session.CheckoutUrl, false);
Context.ApplicationInstance.CompleteRequest();
}
处理 Webhook 时必须验证签名,同时防止重复通知导致重复发货:
protected void Page_Load(object sender, EventArgs e)
{
string payload;
using (StreamReader reader = new StreamReader(Request.InputStream))
{
payload = reader.ReadToEnd();
}
string signature = Request.Headers["X-Payment-Signature"];
if (!PaymentGateway.VerifyWebhookSignature(payload, signature))
{
Response.StatusCode = 400;
return;
}
PaymentNotification notification =
PaymentGateway.ParseNotification(payload);
Order order = OrderRepository.GetByReference(
notification.OrderReference);
bool valid =
notification.Status == "paid" &&
notification.Amount == order.ExpectedAmount &&
notification.Currency == order.Currency;
if (!valid)
{
Response.StatusCode = 400;
return;
}
// 数据库更新应具有幂等性,同一个支付通知只能生效一次。
OrderRepository.MarkPaidOnce(
order.Id,
notification.PaymentId);
Response.StatusCode = 200;
}
X-Payment-Signature、状态值和验签方法都只是占位示例,必须替换为所选支付网关规定的名称和算法。密钥应存放在受保护的服务器配置中,不能写入源码、JavaScript 或版本库。
HTTPS 配置要点
证书应由受信任的证书颁发机构签发,并覆盖网站实际使用的域名。配置完成后,要把 HTTP 请求永久重定向到 HTTPS,并将认证 Cookie 和 Session Cookie 设置为仅通过安全连接发送。
ASP.NET 可以在 web.config 中启用安全 Cookie:
<configuration>
<system.web>
<httpCookies requireSSL="true" httpOnlyCookies="true" />
<forms requireSSL="true" />
</system.web>
</configuration>
HTTP 到 HTTPS 的重定向最好由 IIS、反向代理或负载均衡器处理。如果只能在应用层完成,可以使用类似下面的逻辑:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (!Request.IsSecureConnection)
{
string secureUrl =
"https://" + Request.Url.Host + Request.RawUrl;
Response.Redirect(secureUrl, true);
}
}
如果网站部署在反向代理、CDN 或负载均衡器之后,Request.IsSecureConnection 可能无法反映用户实际使用的协议。此时应由可信代理传递协议状态,并按照代理厂商提供的配置方式进行判断。不要无条件信任公网请求携带的任意转发头。
此外还要完成以下配置:
- 禁用过时的 SSL/TLS 协议和弱加密套件。
- 确认应用能够使用支付网关要求的 TLS 版本建立连接。
- 等 HTTPS 稳定运行后启用 HSTS。
- 避免 HTTPS 页面加载 HTTP 图片、脚本或样式,以免产生 mixed content。
- 不要在日志中记录密码、完整银行卡号、CVV、API secret,或原始支付报文中的敏感字段。
- 为登录、结账和支付接口配置 CSRF 防护与合理的频率限制。
关于主机费用
启用 HTTPS 不等于必须购买价格翻倍的服务器。额外成本可能来自证书、独立 IP、托管套餐限制或服务商的代管费用。部分较老的 Windows 主机不支持 SNI,因此要求每张证书使用独立 IP;现代托管环境通常没有这个限制。
在购买 £39.99 或 £89.99 的方案前,应先向主机商确认:
- 较低价套餐是否允许安装自有 TLS 证书。
- 差价来自证书、独立 IP,还是服务器规格。
- 是否支持证书自动续期。
- 支持哪些 TLS 版本。
- 能否通过反向代理或 CDN 终止 TLS。
- ASP.NET 2.0 应用调用支付 API 时,是否兼容对方要求的 TLS 版本。
如果低价套餐无法可靠提供 HTTPS,就不适合作为电商网站的正式生产环境。此时应更换套餐或主机商,而不是取消 HTTPS。
最后需要注意
支付系统的主要风险通常不在于选择了哪个支付控件,而在于应用会直接接触多少银行卡数据。由成熟的支付服务商托管银行卡输入和验证流程,通常比在 ASP.NET 2.0 中自行开发支付表单更安全,也更容易维护。
合理的方案是升级技术平台、全站启用 HTTPS、采用 Hosted Checkout 或 Tokenization,通过服务器端 Webhook 验签确认支付,并将主机安全、证书维护和支付合规纳入上线所需的必要成本。
备注:内容仅供参考。
