我有一个Android客户端,可将JSON数据发送到我的Spring Boot应用程序服务器。
为了在通信过程中保持一定水平的数据完整性,我要求对原始有效负载进行哈希处理,然后将其与原始JSON数据一起设置为传出有效负载。
这是我的意思(Android客户端)
signUpUserRequest = new SignUpUserRequest(
lastName.getText().toString(),
Long.valueOf(phoneNumber.getText().toString().trim()),
emailAddress.getText().toString(),
Config.getAndroidId(this),
Type.INDIVIDUAL.toString(),
firstName.getText().toString(),
Config.ToBase64Encode(confirmPassword.getText().toString())
);
signUpUserRequest.setHash(Config.HashString(signUpUserRequest.toDataString().trim()));
下面是SignUpUserRequest
Pojo(为简便起见,删除了Setter和getter)
public class SignUpUserRequest {
private String firstName;
private String lastName;
private long phoneNumber;
private String type;
private String email;
private String password;
private String phoneId;
private String hash;
public SignUpUserRequest(String lastName, Long phoneNumber, String email, String phoneId, String type, String firstName, String password) {
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.email = email;
this.phoneId = phoneId;
this.type = type;
this.firstName = firstName;
this.password = password;
}
.... setters and getters removed ....
public String toDataString() {
return "SignUpUserRequest{" + "firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber=" + phoneNumber + ", type=" + type + ", email=" + email + ", password=" + password + ", phoneId=" + phoneId + '}';
}
@Override
public String toString() {
return "SignUpUserRequest{" + "firstName=" + firstName + ", lastName=" + lastName + ", phoneNumber=" + phoneNumber + ", type=" + type + ", email=" + email + ", password=" + password + ", phoneId=" + phoneId + ", hash=" + hash + '}';
}
我遇到的问题是,当我将JSON发送到spring boot应用程序,然后对请求数据执行完整性检查时,服务器端生成的哈希值始终与客户端端生成的哈希值不同。
服务器端代码(Spring启动应用程序)
public ResponseEntity getSignupSessionJWTToken(@RequestBody SignUpUserRequest request) {
Response response = new Response();
String hashString = Config.HashString(request.toDataString().trim());
if (hashString.equals(request.getHash())) {
...... do anything here .....
}else{
..... integrity exception ....
}
所以我的问题是正确的方法吗? 我是从根本上做错了什么吗?如何最好地实现客户端和服务器之间的数据完整性。
hashString
(Android)的实现
public static String HashString(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.trim().getBytes("UTF-8"));
Log.i("CONFIG", "HASHING TEXT = " + ToBase64Encode(hash));
return ToBase64Encode(hash);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, ex);
return "";
} catch (UnsupportedEncodingException e) {
Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, e);
return "";
}
}
public static String ToBase64Encode(byte[] originalInput) {
return new String(Base64.encodeToString(originalInput, Base64.DEFAULT));
}
hashString
(SpringBoot)的实现
public static String HashString(String text) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
// System.out.println("Compare this = " + ToBase64Encode(hash));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(RiceHelper.class.getName()).log(Level.SEVERE, null, ex);
return "";
}
}
答案 0 :(得分:1)
客户端的base64输出不安全,因为它在编码时使用Base64.DEFAULT标志。当在服务器端接收到编码结果时,“ +”字符将转换为“-”字符。因此,比较失败。为了验证这一点,您可以从客户端发送的编码base64字符串以及从服务器端接收的字符串。
要使其网址安全,请使用-
byte[] encoded = Base64.encode(
strBytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
答案 1 :(得分:0)
您可以将HashString方法放入SignUpUserRequest中,并在两端使用它。 如前所述,作为攻击的一部分,攻击者可以自己更改哈希,从而使您无法通过检查-这是否是问题,取决于您要缓解的威胁。如果您想适当保护邮件,请看一下DSA(数字安全算法)。
对于大多数实施方式,您可以只通过https发送注册,并依靠SSL连接来确保完整性。