Atlassian Connect应用JWT认证漏洞修复求助(Ruby on Rails)
修复Atlassian Connect应用JWT认证漏洞(Ruby on Rails)
问题背景
我在Atlassian应用市场上架的Connect应用未通过JWT认证漏洞扫描工具检测,漏洞描述如下:
Connect安全要求测试工具的EcoScanner检查项“应用资源认证”报告了以下问题:
一个或多个端点在未提供认证信息的情况下返回了<400状态码。这可能表明您的应用未执行认证与授权检查。扫描工具使用的JWT令牌为测试用伪造令牌。注意:若您认为报告的端点确实无需认证,请在漏洞工单中发起复核,Atlassian EcoAppSec团队将进行核查。
我的应用基于Ruby on Rails开发,已尝试编写校验POST请求JWT令牌的方法并在Webhook端点使用,但问题仍未解决。当前校验代码如下:
def check_jwt(user) authorization_header = request.headers['Authorization'] # Ensure the Authorization header exists and starts with "JWT " if authorization_header&.start_with?('JWT ') jwt_token = authorization_header[4..-1] shared_secret = user.shared_secret begin decoded_token = JWT.decode(jwt_token, shared_secret, true, algorithm: 'HS256') rescue JWT::DecodeError => e render json: { error: 'Unauthorized' }, status: :unauthorized raise e # Raise an exception to halt further execution end # Continue processing with the decoded token # ... else render json: { error: 'Unauthorized' }, status: :unauthorized raise JWT::DecodeError, 'Missing or invalid Authorization header' end end
修复方案
1. 覆盖所有HTTP方法
扫描工具可能测试了GET、PUT等非POST方法的端点,仅针对POST做校验远远不够。必须确保所有对外暴露的端点,无论请求方法,都执行JWT认证校验。
2. 修复校验逻辑的核心缺陷
- 状态码合规性:未认证请求必须返回
401 Unauthorized,而非400。你的代码虽指定了:unauthorized,但要确认无中间件篡改状态码(Rails默认映射401,需排查)。 - 异常处理全覆盖:
JWT.decode会抛出多种异常(如JWT::ExpiredSignature、JWT::InvalidIssuerError),当前仅捕获JWT::DecodeError,需统一处理所有JWT相关异常。 - 确保请求彻底终止:
render后raise异常可能被其他rescue捕获,导致请求继续处理。建议用head :unauthorized后直接return,或在Rails控制器中用throw :abort彻底终止请求。
修改后的校验方法示例:
def check_jwt(user) authorization_header = request.headers['Authorization'] # 校验Authorization头格式 unless authorization_header&.start_with?('JWT ') head :unauthorized return end jwt_token = authorization_header[4..-1] shared_secret = user.shared_secret begin decoded_token = JWT.decode(jwt_token, shared_secret, true, algorithm: 'HS256') # 可选增强:校验令牌的issuer、audience等字段符合Atlassian规范 # issuer = decoded_token[0]['iss'] # unless issuer == "https://#{user.atlassian_domain}" # head :unauthorized # return # end rescue JWT::DecodeError, JWT::ExpiredSignature, JWT::InvalidIssuerError => e head :unauthorized return end # 校验通过,继续处理请求 end
3. 全局应用认证校验(推荐)
不要仅在Webhook端点手动调用校验,建议用Rails的before_action全局应用到所有控制器,或指定路由组:
# 在ApplicationController中添加全局前置校验 before_action :check_jwt private def check_jwt # 根据租户标识获取对应用户(比如从请求头或令牌解析) tenant_id = request.headers['X-Atlassian-Tenant-Id'] user = User.find_by(tenant_id: tenant_id) unless user head :unauthorized return end # 执行JWT校验逻辑 authorization_header = request.headers['Authorization'] unless authorization_header&.start_with?('JWT ') head :unauthorized return end jwt_token = authorization_header[4..-1] shared_secret = user.shared_secret begin JWT.decode(jwt_token, shared_secret, true, algorithm: 'HS256') rescue JWT::DecodeError, JWT::ExpiredSignature, JWT::InvalidIssuerError => e head :unauthorized return end end
4. 排查未覆盖的端点
- 检查所有路由是否都应用了校验,包括静态资源、健康检查端点(若健康检查无需认证,需在漏洞工单中说明并申请复核)。
- 重新运行扫描工具,确认所有未认证请求均返回401状态码。
内容的提问来源于stack exchange,提问作者Hakeem Baba
相关产品推荐
相关产品推荐

