IT박스

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

itboxs 2020. 7. 7. 07:57
반응형

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


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

요구 사항 :

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

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


이를 수행하는 간단한 방법은 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에 키 저장소가있는 경우이를 사용하여 구성 또는 기타 파일에서 중요한 데이터를 암호화하고 암호 해독해야하는 암호화 키를 저장할 수 있습니다.


Check out jasypt, which is a library offering basic encryption capabilities with minimum effort.


I think that the best approach is to ensure that your config file (containing your password) is only accessible to a specific user account. For example, you might have an application specific user appuser to which only trusted people have the password (and to which they su to).

That way, there's no annoying cryptography overhead and you still have a password which is secure.

EDIT: I am assuming that you are not exporting your application configuration outside of a trusted environment (which I'm not sure would make any sense, given the question)


Well to solve the problems of master password - the best approach is not to store the password anywhere, the application should encrypt passwords for itself - so that only it can decrypt them. So if I was using a .config file I would do the following, mySettings.config:

encryptTheseKeys=secretKey,anotherSecret

secretKey=unprotectedPasswordThatIputHere

anotherSecret=anotherPass

someKey=unprotectedSettingIdontCareAbout

so I would read in the keys that are mentioned in the encryptTheseKeys, apply the Brodwalls example from above on them and write them back to the file with a marker of some sort (lets say crypt:) to let the application know not to do it again, the output would look like this:

encryptTheseKeys=secretKey,anotherSecret

secretKey=crypt:ii4jfj304fjhfj934fouh938

anotherSecret=crypt:jd48jofh48h

someKey=unprotectedSettingIdontCareAbout

Just make sure to keep the originals in your own secure place...


The big point, and the elephant in the room and all that, is that if your application can get hold of the password, then a hacker with access to the box can get hold of it too!

The only way somewhat around this, is that the application asks for the "master password" on the console using Standard Input, and then uses this to decrypt the passwords stored on file. Of course, this completely makes is impossible to have the application start up unattended along with the OS when it boots.

However, even with this level of annoyance, if a hacker manages to get root access (or even just access as the user running your application), he could dump the memory and find the password there.

The thing to ensure, is to not let the entire company have access to the production server (and thereby to the passwords), and make sure that it is impossible to crack this box!


Try using ESAPIs Encryption methods. Its easy to configure and you can also easily change your keys.

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

You

1)encrypt 2)decrypt 3)sign 4)unsign 5)hashing 6)time based signatures and much more with just one library.


See what is available in Jetty for storing password (or hashes) in configuration files, and consider if the OBF encoding might be useful for you. Then see in the source how it is done.

http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html


Depending on how secure you need the configuration files or how reliable your application is, http://activemq.apache.org/encrypted-passwords.html may be a good solution for you.

If you are not too afraid of the password being decrypted and it can be really simple to configure using a bean to store the password key. However, if you need more security you can set an environment variable with the secret and remove it after launch. With this you have to worry about the application / server going down and not application not automatically relaunching.


If you are using java 8 the use of the internal Base64 encoder and decoder can be avoided by replacing

return new BASE64Encoder().encode(bytes);

with

return Base64.getEncoder().encodeToString(bytes);

and

return new BASE64Decoder().decodeBuffer(property);

with

return Base64.getDecoder().decode(property);

Note that this solution doesn't protect your data as the methods for decrypting are stored in the same place. It just makes it more difficult to break. Mainly it avoids to print it and show it to everybody by mistake.

참고URL : https://stackoverflow.com/questions/1132567/encrypt-password-in-configuration-files

반응형