如何在Heroku部署的Django项目中安全接入支付功能?
Django + Heroku 接入Stripe支付防私钥暴露落地方案
核心原则先记死:Stripe sk开头的私钥绝对不能出现在任何用户可访问的前端代码、静态资源、明文提交到代码仓库的配置中,所有涉及私钥的操作全部收敛到Django服务端处理,前端仅可接触pk开头的公钥、单次支付生成的临时client_secret,从流程上堵死泄露可能。
1. 先做密钥隔离,从配置层杜绝硬编码泄露
- 不要在Django的
settings.py或任何代码文件里明文写Stripe密钥,直接在Heroku后台的Config Vars中配置两个环境变量:STRIPE_SECRET_KEY:填入Stripe后台获取的sk开头私钥STRIPE_PUBLISHABLE_KEY:填入pk开头公钥,该密钥可公开,用于前端初始化Stripe
- Django侧读取环境变量的配置写法:
# settings.py import os STRIPE_SECRET_KEY = os.getenv("STRIPE_SECRET_KEY") STRIPE_PUBLISHABLE_KEY = os.getenv("STRIPE_PUBLISHABLE_KEY")
- 本地调试时,在项目根目录新建
.env文件存放上述两个密钥值,同时把.env加入.gitignore列表,绝对不要把该文件提交到Git仓库,本地可通过python-dotenv加载环境变量即可。
2. 按标准前后端分工实现支付流程,全程私钥不触达前端
整个流程严格按以下逻辑写,不要图省事跨层放代码:
- 前端初始化Stripe时仅传入公钥,绝对不要出现私钥:
// 前端支付页JS代码,公钥可通过模板渲染注入或后端接口返回 const stripe = Stripe('{{ STRIPE_PUBLISHABLE_KEY }}');
- 创建支付单、校验支付结果、处理退款等需要账户权限的操作,全部封装为Django接口,在服务端初始化Stripe客户端调用私钥,最小可用示例:
# views.py import stripe from django.conf import settings from django.http import JsonResponse # 私钥仅在服务端内存中初始化,不会随响应返回给前端 stripe.api_key = settings.STRIPE_SECRET_KEY def create_payment_intent(request): # 替换为自身业务的订单金额计算逻辑,注意Stripe金额单位为对应币种的最小分度值(如美元为分) payment_intent = stripe.PaymentIntent.create( amount=1999, # 对应19.99美元 currency='usd', metadata={'order_id': request.POST.get('order_id')} # 可塞入自身系统订单号用于后续对账 ) # 仅返回单次支付对应的临时client_secret给前端,该凭证仅能操作当前这一笔支付,无账户权限风险 return JsonResponse({'client_secret': payment_intent.client_secret})
- 前端拿到接口返回的
client_secret后,直接调用Stripe官方的支付组件(如Elements、Checkout)完成支付即可,不需要额外传其他敏感参数。
3. Heroku部署额外注意事项
- 不要在代码中加打印密钥的调试逻辑,避免密钥输出到Heroku部署日志造成泄露
- Stripe支付结果回调(Webhook)的签名校验密钥同样存入Heroku Config Vars,校验逻辑全部在Django后端实现,不要把签名密钥传到前端
- 本地调试Webhook时用Stripe CLI做请求转发即可,不要硬编码Webhook密钥到代码中
- 每次代码提交前,全局搜索下仓库内是否存在
sk_开头的字符串,一旦发现立刻删除,同时到Stripe后台轮换作废已泄露的旧密钥,不要抱有侥幸心理
常见踩坑避坑
- 但凡你在HTML模板、前端JS、静态资源文件里看到sk开头的Stripe密钥,100%属于私钥暴露,立刻整改
- 不要为了省事儿把Stripe客户端初始化全写在前端,哪怕你加了所谓的接口权限校验也没用,前端代码用户可以直接通过浏览器查看源码拿到所有明文内容
- 不要把包含密钥的本地配置文件提交到公开或私有代码仓库,哪怕是私有仓库也有泄露风险
内容的提问来源于stack exchange,提问作者bernardo
相关产品推荐
相关产品推荐

