[java] 구성 파일에서 비밀번호를 암호화 하시겠습니까? [닫은]

구성 파일에서 서버 정보를 읽고 프로그램에서 읽고 해독 할 수있는 해당 구성의 비밀번호를 암호화하려는 프로그램이 있습니다.

요구 사항 :

  • 일반 텍스트 비밀번호를 암호화하여 파일에 저장
  • 내 프로그램에서 파일에서 읽은 암호화 된 비밀번호 해독

내가 어떻게 할 것인가에 대한 추천은 무엇입니까? 내 자신의 알고리즘을 작성하려고 생각했지만 그것이 매우 안전하지 않을 것이라고 생각합니다.



답변

이를 수행하는 간단한 방법은 Java에서 비밀번호 기반 암호화를 사용하는 것입니다. 암호를 사용하여 텍스트를 암호화하고 해독 할 수 있습니다.

이것은 기본적으로 초기화 의미 javax.crypto.Cipher알고리즘 "AES/CBC/PKCS5Padding"과에서 키를 받고 javax.crypto.SecretKeyFactory"PBKDF2WithHmacSHA512"알고리즘입니다.

다음은 코드 예제입니다 (보안이 덜한 MD5 기반 변형을 대체하도록 업데이트 됨).

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class ProtectedConfigFile {

    public static void main(String[] args) throws Exception {
        String password = System.getProperty("password");
        if (password == null) {
            throw new IllegalArgumentException("Run with -Dpassword=<password>");
        }

        // The salt (probably) can be stored along with the encrypted data
        byte[] salt = new String("12345678").getBytes();

        // Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
        int iterationCount = 40000;
        // Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
        int keyLength = 128;
        SecretKeySpec key = createSecretKey(password.toCharArray(),
                salt, iterationCount, keyLength);

        String originalPassword = "secret";
        System.out.println("Original password: " + originalPassword);
        String encryptedPassword = encrypt(originalPassword, key);
        System.out.println("Encrypted password: " + encryptedPassword);
        String decryptedPassword = decrypt(encryptedPassword, key);
        System.out.println("Decrypted password: " + decryptedPassword);
    }

    private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
        PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
        SecretKey keyTmp = keyFactory.generateSecret(keySpec);
        return new SecretKeySpec(keyTmp.getEncoded(), "AES");
    }

    private static String encrypt(String property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException {
        Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        pbeCipher.init(Cipher.ENCRYPT_MODE, key);
        AlgorithmParameters parameters = pbeCipher.getParameters();
        IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
        byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8"));
        byte[] iv = ivParameterSpec.getIV();
        return base64Encode(iv) + ":" + base64Encode(cryptoText);
    }

    private static String base64Encode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
        String iv = string.split(":")[0];
        String property = string.split(":")[1];
        Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
        return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
    }

    private static byte[] base64Decode(String property) throws IOException {
        return Base64.getDecoder().decode(property);
    }
}

한 가지 문제가 남아 있습니다. 비밀번호를 암호화하는 데 사용하는 비밀번호를 어디에 저장해야합니까? 소스 파일에 저장하여 난독 처리 할 수 ​​있지만 다시 찾기가 어렵지 않습니다. 또는 Java 프로세스를 시작할 때 시스템 특성으로 제공 할 수 있습니다 ( -DpropertyProtectionPassword=...).

비밀번호로 보호되는 KeyStore를 사용하는 경우에도 동일한 문제가 남아 있습니다. 기본적으로 어딘가에 하나의 마스터 암호가 있어야하며 보호하기가 어렵습니다.


답변

예, 확실히 자신의 알고리즘을 작성하지 마십시오. Java에는 많은 암호화 API가 있습니다.

설치하려는 OS에 키 저장소가있는 경우이를 사용하여 구성 또는 기타 파일에서 중요한 데이터를 암호화하고 암호 해독해야하는 암호화 키를 저장할 수 있습니다.


답변

최소한의 노력으로 기본 암호화 기능을 제공하는 라이브러리 인 jasypt를 확인하십시오 .


답변

최선의 접근 방식은 구성 파일 (비밀번호 포함)이 특정 사용자 계정에서만 액세스 할 수 있도록하는 것 입니다. 예를 들어, appuser신뢰할 수있는 사람 만 암호를 가진 응용 프로그램 특정 사용자 가있을 수 있습니다.su .

그렇게하면 성가신 암호화 오버 헤드가 없으며 여전히 안전한 암호가 있습니다.

편집 : 신뢰할 수있는 환경 외부에서 응용 프로그램 구성을 내 보내지 않는다고 가정합니다 (질문이 주어지면 확실하지 않습니다)


답변

마스터 비밀번호의 문제를 해결하는 것이 가장 좋습니다. 가장 좋은 방법은 비밀번호를 아무 곳에 나 저장하지 않는 것입니다. 애플리케이션은 비밀번호 자체를 암호화하여 비밀번호 만 해독 할 수 있습니다. 따라서 .config 파일을 사용하는 경우 다음 mySettings.config를 수행합니다 .

encryptTheseKeys = secretKey, 다른 비밀

secretKey = 비보호 암호 ThatIput 여기

anotherSecret = anotherPass

someKey = unprotectedSettingIdontCare 정보

그래서 encryptTheseKeys에 언급 된 키를 읽고 위에서 Brodwalls 예제를 적용하고 일종의 마커 ( crypt 라고 말 하십시오 )로 파일에 다시 써서 응용 프로그램이하지 말라고 알리십시오. 다시 출력은 다음과 같습니다.

encryptTheseKeys = secretKey, 다른 비밀

secretKey = 암호 : ii4jfj304fjhfj934fouh938

anotherSecret = 암호 : jd48jofh48h

someKey = unprotectedSettingIdontCare 정보

원본을 안전한 곳에 보관하십시오 …


답변

가장 큰 요점과 방 안의 코끼리는 응용 프로그램이 암호를 파악할 수 있으면 상자에 액세스 할 수있는 해커도 암호를 얻을 수 있다는 것입니다!

이 문제를 해결하는 유일한 방법은 응용 프로그램이 표준 입력을 사용하여 콘솔에서 “마스터 암호”를 요청한 다음이를 사용하여 파일에 저장된 암호를 해독하는 것입니다. 물론, 부팅 할 때 OS와 함께 응용 프로그램을 자동으로 시작하는 것은 불가능합니다.

그러나 이러한 수준의 성가심에도 불구하고 해커가 루트 액세스 권한을 얻거나 응용 프로그램을 실행하는 사용자로 액세스 할 수 있다면 메모리를 덤프하고 거기에서 암호를 찾을 수 있습니다.

보장해야 할 것은 회사 전체가 프로덕션 서버에 액세스하여 암호에 액세스하지 못하게하고이 상자를 해독 할 수 없도록하는 것입니다!


답변

ESAPIs 암호화 방법을 사용해보십시오. 구성하기 쉽고 키를 쉽게 변경할 수도 있습니다.

http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html

당신

1) 암호화 2) 복호화 3) 서명 4) 서명 해제 5) 해싱 6) 시간 기반 서명 및 단 하나의 라이브러리로 훨씬 더.