MD5 Подписание HttpServletResponse - PullRequest
6 голосов
/ 02 февраля 2010

Я ищу способ проверить содержимое HttpServletResponse, чтобы подписать его хешем MD5.

Псевдокод может выглядеть следующим образом

process(Response response, Request request){

defaultProcessingFor(response,request);

dispatcher.handle(response,request);

// Here I want to read the contents of the Response object (now filled with data) to create a MD5 hash with them and add it to a header.
}

Возможно ли это?

Ответы [ 3 ]

6 голосов
/ 02 февраля 2010

Да, это возможно. Вам необходимо оформить ответ с помощью HttpServletResponseWrapper, в котором вы замените ServletOutputStream пользовательской реализацией, которая записывает байты как в дайджест MD5, так и в «исходный» выходной поток , Наконец, предоставьте средство доступа для получения окончательной суммы MD5.

Обновление Я просто ради забавы немного поиграл, вот пример для начала:

Упаковщик ответов:

public class MD5ServletResponse extends HttpServletResponseWrapper {

    private final MD5ServletOutputStream output;
    private final PrintWriter writer;

    public MD5ServletResponse(HttpServletResponse response) throws IOException {
        super(response);
        output = new MD5ServletOutputStream(response.getOutputStream());
        writer = new PrintWriter(output, true);
    }

    public PrintWriter getWriter() throws IOException {
        return writer;
    }

    public ServletOutputStream getOutputStream() throws IOException {
        return output;
    }

    public byte[] getHash() {
        return output.getHash();
    }

}

Выходной поток MD5:

public class MD5ServletOutputStream extends ServletOutputStream {

    private final ServletOutputStream output;
    private final MessageDigest md5;

    {
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public MD5ServletOutputStream(ServletOutputStream output) {
        this.output = output;
    }

    public void write(int i) throws IOException {
        byte[] b = { (byte) i };
        md5.update(b);
        output.write(b, 0, 1);
    }

    public byte[] getHash() {
        return md5.digest();
    }

}

Как это использовать:

// Wrap original response with it:
MD5ServletResponse md5response = new MD5ServletResponse(response);

// Now just use md5response instead or response, e.g.:
dispatcher.handle(request, md5response);

// Then get the hash, e.g.:
byte[] hash = md5response.getHash();
StringBuilder hashAsHexString = new StringBuilder(hash.length * 2);
for (byte b : hash) {
    hashAsHexString.append(String.format("%02x", b));
}
System.out.println(hashAsHexString); // Example af28cb895a479397f12083d1419d34e7.
1 голос
/ 02 февраля 2010

Технически, термин «подпись» зарезервирован для сигнатур, а хэш-функции их не вычисляют.

Чтобы гарантировать, что данные не были изменены при передаче с помощью хеш-функции, тогда у вас должен быть безопасный внеполосный способ передачи хеш-значения; добавление значения хеша в заголовки HTTP не поможет, потому что любой, кто может изменить передаваемые данные, может пересчитать хеш по своему усмотрению и изменить заголовки HTTP, как он считает нужным.

С помощью криптографии вы можете «сконцентрировать» эту защищенную внеполосную передачу в ключе многократного использования. Если клиент и сервер имеют общее секретное значение, неизвестное предполагаемому злоумышленнику, тогда аббревиатурой является MAC, как в «Коде аутентификации сообщения»; обычный MAC это HMAC .

Во многих практических ситуациях MAC нельзя использовать, потому что MAC требует общего секрета, а секрет, который делился слишком много раз, больше не является секретом. Каждый секретный владелец имеет право пересчитать MAC. Если каждый клиент знает секрет, то в основном это не секрет, и можно предположить, что злоумышленник также знает его. Следовательно, вы можете пойти еще дальше и использовать цифровые подписи (реальные, которые используют RSA, DSS, ECDSA ...), в которых сервер использует закрытый ключ (который знает только сервер), а клиенты знают только соответствующий открытый ключ . Знание открытого ключа достаточно для проверки подписей, но не для создания новых, и закрытый ключ не может быть пересчитан из открытого ключа (хотя они математически связаны друг с другом). Однако внедрение цифровой подписи и ее правильное использование намного сложнее, чем обычно предполагается; тогда лучше всего использовать уже отлаженный протокол с существующими реализациями, и этот протокол называется «SSL».

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

0 голосов
/ 02 февраля 2010

Что вы пытаетесь сделать?

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

Также, если вы включите SSL, клиент может быть уверен, что содержимое ответа не было подделано.

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