Postman正常的AWS Prometheus GET请求,Java HttpURLConnection返回403
调用Amazon Prometheus Server时Java HttpURLConnection返回403认证错误
我使用Postman请求Amazon Prometheus Server可正常返回结果,但通过Java的HttpURLConnection发起相同请求时,却返回403认证错误,认证采用AWS Signature Version 4签名机制。
Postman请求头(敏感信息已隐藏)
GET https://{resource}-workspaces.us-east-1.amazonaws.com/XXXXXXXXXXX/api/v1/query Host: {resource}-workspaces.us-east-1.amazonaws.com X-Amz-Security-Token: FwoGZXIvYXdzEB4aDPxYxIKgd5JznR9gOyKkAkoDbjeTi79mRDgU6Hdd2AGlLwKnNGySAkNYwmKItTcSssS9zNZ+/s..........................................== X-Amz-Date: 20221207T201649Z Authorization: AWS4-HMAC-SHA256 Credential={AccessKey}/20221207/us-east-1/{Resource}/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=XXXXXXXXXXXXXXXXXXXXXXXXXX User-Agent: PostmanRuntime/7.29.0 Accept: */* Cache-Control: no-cache Postman-Token: ea3f71dd-db52-4869-a48a-2cf5f72d15b3 Accept-Encoding: gzip, deflate, br Connection: keep-alive
Java HttpURLConnection代码
try { final URL url = new URL("https://{resource}-workspaces.us-east-1.amazonaws.com/XXXXXXXXXXX/api/v1/query"); final HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); httpConn.setRequestMethod("GET"); httpConn.setRequestProperty("Host", "{resource}-workspaces.us-east-1.amazonaws.com"); httpConn.setRequestProperty("X-Amz-Security-Token", "FwoGZXIvYXdzEB4aDPxYxIKgd5JznR9gOyKkAkoDbjeTi79mRDgU6Hdd2AGlLwKnNGySAkNYwmKItTcSssS9zNZ+/s..........................................=="); httpConn.setRequestProperty("X-Amz-Date", "20221207T201649Z"); httpConn.setRequestProperty("Authorization", "AWS4-HMAC-SHA256 Credential={AccessKey}/20221207/us-east-1/{Resource}/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=XXXXXXXXXXXXXXXXXXXXXXXXXX"); httpConn.setRequestProperty("User-Agent", "Mozilla/5.0"); httpConn.setRequestProperty("Accept", "`*`/`*`"); httpConn.setRequestProperty("Cache-Control", "no-cache"); httpConn.setRequestProperty("Postman-Token", "ea3f71dd-db52-4869-a48a-2cf5f72d15b3"); httpConn.setRequestProperty("Accept-Encoding", "gzip, deflate, br"); httpConn.setRequestProperty("Connection", "keep-alive"); responseCode = httpConn.getResponseCode(); // 此处返回403 }
已尝试的方案
- 自行生成签名,而非复用Postman生成的签名
- 添加/移除部分请求头,包括User-Agent、Accept、Cache-Control、Postman-Token、Accept-Encoding、Connection
请问是什么原因导致了403响应?我使用AWS Signature Version 4签名请求AWS服务,期望返回200,但实际得到403。
问题分析与解决建议
请求头格式错误
你代码里的Accept头写了"*/*",多余的反引号会导致请求头内容和签名生成时的预期不一致,AWS验证签名时会直接拒绝,改成"*/*"即可。X-Amz-Date过期
代码里复用了Postman的固定时间戳20221207T201649Z,AWS SigV4要求请求时间和签名时间差不能超过15分钟,过期的时间戳会直接触发403。即使自行生成签名,也要确保X-Amz-Date用当前请求的实时时间,且和签名生成时的时间完全一致。签名与请求头的一致性问题
AWS SigV4会校验SignedHeaders里指定的所有请求头,任何不一致都会导致验证失败:- 手动设置的
Host头可能和HttpURLConnection自动生成的冲突,建议去掉手动设置,让框架自动从URL提取 Postman-Token是Postman的自定义头,不需要在Java请求中发送,如果签名时包含了这个头但实际没发,或者反之,都会导致签名不匹配
- 手动设置的
HttpURLConnection自动行为干扰
框架会自动处理Connection、Accept-Encoding这类头,手动设置可能和自动生成的内容冲突,比如编码格式的细节差异,建议只保留签名必需的头(X-Amz-Date、X-Amz-Security-Token、Authorization、User-Agent),其余交给框架处理。
内容的提问来源于stack exchange,提问作者blake
相关产品推荐
相关产品推荐

