处理源$ C ​​$ C用于身份验证的密码 [英] Handling passwords used for auth in source code

查看:160
本文介绍了处理源$ C ​​$ C用于身份验证的密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我试图从使用基本身份验证/认证基本一个RESTful API提取,这将是存储在我的程序,用户名和密码的最佳方式?现在,它只是坐在那里的明文。

Assuming that I'm trying to pull from a RESTful api that uses basic authentication / basic certificates, what would be the best way to store that user name and password in my program? Right now it's just sitting there in plaintext.

UsernamePasswordCredentials creds = new UsernamePasswordCredentials("myName@myserver","myPassword1234");

是否有这样做是比较安全的意识?

Is there some way of doing this that is more security minded?

感谢

推荐答案

通过内到外的心态,这里有一些步骤来保护您的过程:

With an inner-to-outer mindset, here are some steps to protect your process:

第一步,你应该更改您的密码处理从字符串字符数组

First step, you should change your password-handling from String to character array.

这样做的原因是,字符串对象的数据不会被立即清洗,即使对象设置为;该数据已设置垃圾收集,而是和这会带来安全问题,因为它被清除之前的恶意程序可能访问到字符串(密码)数据。

The reason for this is that a String object's data will not be cleansed immediately even if the object is set to null; The data is set for garbage-collection instead, and this poses security problems because malicious programs might gain access to that String (password) data before it is cleaned.

这是为什么主要原因<一个href=\"http://docs.oracle.com/javase/6/docs/api/javax/swing/JPasswordField.html#getText%28%29\">Swing's JPasswordField中的的getText() 法德precated,为什么<一个href=\"http://docs.oracle.com/javase/6/docs/api/javax/swing/JPasswordField.html#getPassword%28%29\"><$c$c>getPassword()使用字符数组。

This is the main reason why Swing's JPasswordField's getText() method is deprecated, and why getPassword() uses character arrays.

第二步是加密您的凭据,在认证过程中只能暂时解密他们。

The second step is to encrypt your credentials, only decrypting them temporarily during the authentication process.

此,类似的第一步,可以确保你的漏洞的时间尽可能小。

This, similarly to the first step, makes sure your vulnerability-time is as small as possible.

建议将您的凭据不硬codeD,而相反,你将它们存储在一个集中的,可配置和易于维护的方式,如配置或属性文件中。

It is recommended that your credentials are not hard-coded, and that instead, you store them in a centralized, configurable and easily-maintainable manner, such as a configuration or properties file.

您应该保存文件前加密您的凭据,另外,你可以申请第二加密文件本身(2层加密的凭据,1层到其他文件的内容)。

You should encrypt your credentials before saving the file, and additionally, you can apply a second encryption to the file itself (2-layer encryption to the credentials, and 1-layer to other file contents).

请注意,每个上述两个加密过程可以是多个层次的自己。每个加密可以是三重数据加密标准(又名TDES和3DES)的单个应用程序,作为一个概念上的例子。

Note that each of the two encryption processes mentioned above can be multiple-layered themselves. Each encryption can be an individual application of Triple Data Encryption Standard (AKA TDES and 3DES), as a conceptual example.

本地环境得到适当的保护(!但是请记住,这是从来没有安全)之后,第三步是应用基本保护您的传输过程中,使用的 TLS(传输层安全)或SSL(安全套接字层)

After your local environment is properly protected (but remember, it's never ever "safe"!), the third step is apply basic protection to your transmission process, by using TLS (Transport Layer Security) or SSL (Secure Sockets Layer).

第四步是应用其他保护方法。

The forth step is to apply other protection methods.

例如,应用模糊技术为您的易用编译,以避免(即使不久)的安全性措施的情况下,曝光你的程序是通过的小姐。除夕夜,马洛里先生,或其他人(的坏家伙)和反编译。

For example, applying obfuscation techniques to your "to-use" compile, to avoid (even if shortly) the exposure of your security measures in case your program is obtained by Ms. Eve, Mr. Mallory, or someone else (the bad-guys) and decompiled.

更新1:

通过@ Damien.Bell的要求,这里是覆盖第一和第二步骤的例子:

By @Damien.Bell 's request, here is an example that covers the first and second steps:

    //These will be used as the source of the configuration file's stored attributes.
    private static final Map<String, String> COMMON_ATTRIBUTES = new HashMap<String, String>();
    private static final Map<String, char[]> SECURE_ATTRIBUTES = new HashMap<String, char[]>();
    //Ciphering (encryption and decryption) password/key.
    private static final char[] PASSWORD = "Unauthorized_Personel_Is_Unauthorized".toCharArray();
    //Cipher salt.
    private static final byte[] SALT = {
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
        (byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
    //Desktop dir:
    private static final File DESKTOP = new File(System.getProperty("user.home") + "/Desktop");
    //File names:
    private static final String NO_ENCRYPTION = "no_layers.txt";
    private static final String SINGLE_LAYER = "single_layer.txt";
    private static final String DOUBLE_LAYER = "double_layer.txt";

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws GeneralSecurityException, FileNotFoundException, IOException {
        //Set common attributes.
        COMMON_ATTRIBUTES.put("Gender", "Male");
        COMMON_ATTRIBUTES.put("Age", "21");
        COMMON_ATTRIBUTES.put("Name", "Hypot Hetical");
        COMMON_ATTRIBUTES.put("Nickname", "HH");

        /*
         * Set secure attributes.
         * NOTE: Ignore the use of Strings here, it's being used for convenience only.
         * In real implementations, JPasswordField.getPassword() would send the arrays directly.
         */
        SECURE_ATTRIBUTES.put("Username", "Hypothetical".toCharArray());
        SECURE_ATTRIBUTES.put("Password", "LetMePass_Word".toCharArray());

        /*
         * For demosntration purposes, I make the three encryption layer-levels I mention.
         * To leave no doubt the code works, I use real file IO.
         */
        //File without encryption.
        create_EncryptedFile(NO_ENCRYPTION, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 0);
        //File with encryption to secure attributes only.
        create_EncryptedFile(SINGLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 1);
        //File completely encrypted, including re-encryption of secure attributes.
        create_EncryptedFile(DOUBLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 2);

        /*
         * Show contents of all three encryption levels, from file.
         */
        System.out.println("NO ENCRYPTION: \n" + readFile_NoDecryption(NO_ENCRYPTION) + "\n\n\n");
        System.out.println("SINGLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(SINGLE_LAYER) + "\n\n\n");
        System.out.println("DOUBLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(DOUBLE_LAYER) + "\n\n\n");

        /*
         * Decryption is demonstrated with the Double-Layer encryption file.
         */
        //Descrypt first layer. (file content) (REMEMBER: Layers are in reverse order from writing).
        String decryptedContent = readFile_ApplyDecryption(DOUBLE_LAYER);
        System.out.println("READ: [first layer decrypted]\n" + decryptedContent + "\n\n\n");
        //Decrypt second layer (secure data).
        for (String line : decryptedContent.split("\n")) {
            String[] pair = line.split(": ", 2);
            if (pair[0].equalsIgnoreCase("Username") || pair[0].equalsIgnoreCase("Password")) {
                System.out.println("Decrypted: " + pair[0] + ": " + decrypt(pair[1]));
            }
        }
    }

    private static String encrypt(byte[] property) throws GeneralSecurityException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
        pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));

        //Encrypt and save to temporary storage.
        String encrypted = Base64.encodeBytes(pbeCipher.doFinal(property));

        //Cleanup data-sources - Leave no traces behind.
        for (int i = 0; i < property.length; i++) {
            property[i] = 0;
        }
        property = null;
        System.gc();

        //Return encryption result.
        return encrypted;
    }

    private static String encrypt(char[] property) throws GeneralSecurityException {
        //Prepare and encrypt.
        byte[] bytes = new byte[property.length];
        for (int i = 0; i < property.length; i++) {
            bytes[i] = (byte) property[i];
        }
        String encrypted = encrypt(bytes);

        /*
         * Cleanup property here. (child data-source 'bytes' is cleaned inside 'encrypt(byte[])').
         * It's not being done because the sources are being used multiple times for the different layer samples.
         */
//      for (int i = 0; i < property.length; i++) { //cleanup allocated data.
//          property[i] = 0;
//      }
//      property = null; //de-allocate data (set for GC).
//      System.gc(); //Attempt triggering garbage-collection.

        return encrypted;
    }

    private static String encrypt(String property) throws GeneralSecurityException {
        String encrypted = encrypt(property.getBytes());
        /*
         * Strings can't really have their allocated data cleaned before CG,
         * that's why secure data should be handled with char[] or byte[].
         * Still, don't forget to set for GC, even for data of sesser importancy;
         * You are making everything safer still, and freeing up memory as bonus.
         */
        property = null;
        return encrypted;
    }

    private static String decrypt(String property) throws GeneralSecurityException, IOException {
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
        pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
        return new String(pbeCipher.doFinal(Base64.decode(property)));
    }

    private static void create_EncryptedFile(
                    String fileName,
                    Map<String, String> commonAttributes,
                    Map<String, char[]> secureAttributes,
                    int layers)
                    throws GeneralSecurityException, FileNotFoundException, IOException {
        StringBuilder sb = new StringBuilder();
        for (String k : commonAttributes.keySet()) {
            sb.append(k).append(": ").append(commonAttributes.get(k)).append(System.lineSeparator());
        }
        //First encryption layer. Encrypts secure attribute values only.
        for (String k : secureAttributes.keySet()) {
            String encryptedValue;
            if (layers >= 1) {
                encryptedValue = encrypt(secureAttributes.get(k));
            } else {
                encryptedValue = new String(secureAttributes.get(k));
            }
            sb.append(k).append(": ").append(encryptedValue).append(System.lineSeparator());
        }

        //Prepare file and file-writing process.
        File f = new File(DESKTOP, fileName);
        if (!f.getParentFile().exists()) {
            f.getParentFile().mkdirs();
        } else if (f.exists()) {
            f.delete();
        }
        BufferedWriter bw = new BufferedWriter(new FileWriter(f));
        //Second encryption layer. Encrypts whole file content including previously encrypted stuff.
        if (layers >= 2) {
            bw.append(encrypt(sb.toString().trim()));
        } else {
            bw.append(sb.toString().trim());
        }
        bw.flush();
        bw.close();
    }

    private static String readFile_NoDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
        File f = new File(DESKTOP, fileName);
        BufferedReader br = new BufferedReader(new FileReader(f));
        StringBuilder sb = new StringBuilder();
        while (br.ready()) {
            sb.append(br.readLine()).append(System.lineSeparator());
        }
        return sb.toString();
    }

    private static String readFile_ApplyDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
        File f = new File(DESKTOP, fileName);
        BufferedReader br = new BufferedReader(new FileReader(f));
        StringBuilder sb = new StringBuilder();
        while (br.ready()) {
            sb.append(br.readLine()).append(System.lineSeparator());
        }
        return decrypt(sb.toString());
    }

有一个完整的例子,解决每一个保护步骤,将远远超过什么,我认为是合理的这个问题,因为它是关于是什么的步骤的,不是的如何应用它们

A full example, addressing every protection step, would far exceed what I think is reasonable for this question, since it's about "what are the steps", not "how to apply them".

这将远远超过大小我的答案(最后的采样),而在这里的其他问题上S.O.已经执导的如何的这些步骤,是更为合适的,对每个步骤的实施提供了更好的解释和取样。

It would far over-size my answer (at last the sampling), while other questions here on S.O. are already directed on the "How to" of those steps, being far more appropriate, and offering far better explanation and sampling on the implementation of each individual step.

这篇关于处理源$ C ​​$ C用于身份验证的密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆