Безопасность API: использование хеширования для обеспечения целостности данных между клиентом и сервером - PullRequest
0 голосов
/ 10 января 2019

У меня есть клиент Android, который отправляет данные JSON на мой сервер приложений весенней загрузки.

В других случаях для поддержания определенного уровня целостности данных во время связи мне требуется, чтобы исходная полезная нагрузка хешировалась, а затем устанавливалась в исходящую полезную нагрузку вместе с исходными данными JSON.

Это то, что я имею в виду (Android Client)

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 (для краткости удалены сеттеры и геттеры)

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 в мое приложение весенней загрузки, а затем выполняю проверку целостности данных запроса, хэш, сгенерированный на стороне сервера, всегда отличается от хэша, сгенерированного на стороне клиента.

Код на стороне сервера (приложение для весенней загрузки)

 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 "";
    }
}

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Вывод base64 на стороне клиента не является безопасным Url, поскольку при кодировании он использует флаг Base64.DEFAULT. Символ «+» в закодированном результате преобразуется в символ «-» при получении на стороне сервера. Следовательно, сравнение не удается. Чтобы убедиться в этом, вы можете закодировать строку base64, которую вы отправляете от своего клиента, и строку, которую вы получаете на стороне сервера.

Чтобы сделать URL безопасным, используйте -

byte[] encoded = Base64.encode(
strBytes, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
0 голосов
/ 10 января 2019

Вы можете поместить метод HashString в SignUpUserRequest и использовать его на обоих концах. Как уже упоминалось, злоумышленник может изменить хеш самостоятельно в рамках своей атаки и, таким образом, отменить проверку - зависит ли проблема от угроз, которые вы пытаетесь смягчить. Посмотрите на DSA (алгоритм цифровой защиты), если вы хотите правильно защитить свои сообщения.

Для большинства реализаций вы можете просто отправить свою регистрацию по протоколу https и полностью использовать SSL-соединение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...