programing

비밀번호로 String보다 char[]가 선호되는 이유는 무엇입니까?

newsource 2022. 8. 24. 23:59

비밀번호로 String보다 char[]가 선호되는 이유는 무엇입니까?

에는 Swing이 .getPassword() (비밀(이행)char[]인 ""가 ") getText() (비밀(이행)String 방식입니다.마찬가지로, 저는 이 제품을 사용하지 말자는 제안을 받았습니다.String패스워드를 처리합니다.

?는 왜?String밀번호에 해안?? 안?? ????하기 char[].

끈은 불변이다.즉, 일단 이 시스템을 구축한 후자의String다른 프로세스가 메모리를 덤프할 수 있는 경우 가비지 컬렉션이 시작되기 에 데이터를 삭제할 수 없습니다(반사에서 제외).

어레이를 사용하면 데이터를 모두 삭제한 후 데이터를 명시적으로 삭제할 수 있습니다.어레이를 원하는 것으로 덮어쓸 수 있으며 가비지 수집 전부터 시스템 어디에도 암호가 없습니다.

네, 이것은 보안상의 문제이지만char[]공격자의 기회만 단축할 뿐이며, 이러한 유형의 공격에만 해당됩니다.

코멘트에 기재되어 있듯이, 가비지 콜렉터에 의해서 이동되고 있는 어레이는, 데이터의 부정한 카피를 메모리에 남길 가능성이 있습니다.이것은 실장 고유의 것이라고 생각합니다.가비지 콜렉터는, 이러한 종류의 처리를 피하기 위해서, 모든 메모리를 클리어 할 수 있습니다.설령 그렇다 해도, 아직 그 시간 동안,char[]에 공격창으로서의 실제 문자를 나타냅니다.

여기 있는 다른 제안들은 타당해 보이지만, 한가지 좋은 이유가 있다.String로그, 모니터, 또는 그 외의 안전하지 않은 장소에 패스워드를 잘못 출력할 가능성이 매우 높아집니다. char[]덜 취약합니다.

다음 사항을 고려하십시오.

public static void main(String[] args) {
    Object pw = "Password";
    System.out.println("String: " + pw);

    pw = "Password".toCharArray();
    System.out.println("Array: " + pw);
}

인쇄:

String: Password
Array: [C@5829428e

공식 문서를 인용하기 위해 Java 암호화 아키텍처 가이드에 다음과 같은 내용을 설명합니다.char[] ★★String패스워드(패스워드 기반 암호화에 관한 것이지만, 이것은 물론 보다 일반적으로 패스워드에 관한 것입니다).

하여 타입의 됩니다.java.lang.String할 점은 다음과 같습니다.Object이 s450인 sString불변의 되어 있지 않습니다. 「」, 「」, 「」, 「」, 「」, 「」의 할 수 않습니다.String하면, 「」가 됩니다.String사용자 비밀번호 등의 보안상 중요한 정보를 저장하는 데 적합하지 않은 개체입니다..char대신 배열합니다.

Java 프로그래밍 언어에 대한 보안 코딩 가이드라인 2-2 버전 4.0도 이와 유사한 내용을 설명하고 있습니다(원래 로깅 컨텍스트에 있습니다).

가이드라인 2-2: 매우 민감한 정보를 기록하지 마십시오.

사회보장번호(SSN)나 패스워드 등 일부 정보는 매우 민감합니다.이 정보는 관리자라도 필요 이상으로 오래 보관하거나 볼 수 있는 장소에 보관해서는 안 됩니다.예를 들어 로그 파일로 전송하지 않아야 하며 검색을 통해 해당 존재를 탐지해서는 안 됩니다.일부 과도 데이터는 char 배열과 같은 가변 데이터 구조에 보관되어 사용 후 즉시 지워질 수 있습니다.데이터 구조를 클리어하면 오브젝트가 메모리 내에서 프로그래머에게 투과적으로 이동하기 때문에 일반적인 Java 런타임 시스템의 효율성이 저하됩니다.

또한 이 지침은 취급하는 데이터에 대한 의미 지식이 없는 하위 수준의 라이브러리의 구현 및 사용에 영향을 미칩니다.예를 들어 하위 수준의 문자열 구문 분석 라이브러리는 해당 라이브러리가 작동하는 텍스트를 기록할 수 있습니다.응용프로그램은 라이브러리에서 SSN을 구문 분석할 수 있습니다.이로 인해 로그 파일에 액세스할 수 있는 관리자가 SSN을 사용할 수 있는 상황이 발생합니다.

문자 배열(char[]사용 후 각 문자를 0으로 설정하고 Strings를 사용하지 않도록 설정하면 클리어할 수 있습니다.메모리이미지를 볼 수 할 수 , Strings를 사용하면 일반 텍스트로 할 수 .char[]0으로 데이터를 삭제하면 비밀번호가 보호됩니다.

일부 사람들은 더 이상 필요하지 않게 되면 암호를 저장하는 데 사용된 메모리를 덮어써야 한다고 생각합니다.이를 통해 공격자가 시스템에서 암호를 읽어야 하는 시간이 단축되고 공격자가 이를 위해 JVM 메모리를 가로채기 위해 이미 충분한 액세스 권한이 필요하다는 사실을 완전히 무시합니다.그 정도의 접근권을 가진 공격자는 당신의 주요 이벤트를 포착하여 전혀 쓸모없게 할 수 있습니다(AFAIK, 틀렸다면 정정해 주세요).

갱신하다

댓글 덕분에 답변을 업데이트 할 수 있게 되었습니다.하드 드라이브에 패스워드가 저장되는 시간을 단축하기 때문에 (매우) 사소한 보안 향상을 추가할 수 있는 경우는 두 가지가 있는 것 같습니다.여전히 대부분의 사용 사례에서 과잉 살상이라고 생각합니다.

  • 타깃 시스템이 잘못 설정되어 있거나 설정되어 있다고 가정해야 하며 코어 덤프에 대해 편집증이 필요합니다(관리자가 시스템을 관리하지 않는 경우 유효할 수 있습니다).
  • 공격자가 TrueCrypt(중단), VeraCrypt 또는 CipherSheed 등을 사용하여 하드웨어에 액세스할 수 있는 데이터 유출을 방지하기 위해 소프트웨어는 지나치게 편집적이어야 합니다.

가능하면 코어 덤프와 스왑 파일을 디세블로 하면 두 가지 문제가 모두 해결됩니다.다만, 관리자 권한이 필요하게 되어, 기능(사용하는 메모리 부족)이 저하하는 일이 있습니다.실행중인 시스템에서 RAM을 꺼내는 것은 여전히 유효한 문제입니다.

이것은 타당한 제안이 아니라고 생각합니다만, 적어도 그 이유는 짐작할 수 있습니다.

그 이유는 패스워드를 사용한 후 메모리의 모든 흔적을 즉시 확실하게 지울 수 있도록 하기 위해서라고 생각합니다.char[]어레이의 각 요소를 공백 등으로 덮어쓸 수 있습니다.수 .String그와 같이.

왜 그냥 하면 안 요?char[] ★★★★★★★★★★★★★★★★★」String망가지? ??하지만 중요한 건...String에는 '''를 지정할 수 .intern()이론적으로, 그리고 항상 수영장에서 살아있었다.사용하는 것 같습니다.char[]을 사용하다

이미 답변이 있었습니다만, 최근 발견한 문제를 Java 표준 라이브러리와 공유하고 싶습니다.을 「」로 만,char[](물론 좋은 일이지만) 다른 보안 크리티컬 데이터는 메모리에서 삭제할 필요가 없습니다.

를 들어 PrivateKey 클래스를 생각하고 있습니다.PKCS#12 파일에서 개인 RSA 키를 로드하고 이를 사용하여 작업을 수행하는 시나리오를 생각해 보십시오.이 경우 키 파일에 대한 물리적 액세스가 적절하게 제한되는 한 암호를 스니핑하는 것만으로는 큰 도움이 되지 않습니다.공격자는 패스워드 대신 직접 키를 취득하는 것이 훨씬 유리합니다.필요한 정보는 누출될 수 있으며 코어 덤프, 디버거 세션 또는 스왑 파일은 몇 가지 예입니다.

알고 '를 수 도 없습니다.PrivateKey해당 정보를 구성하는 바이트를 삭제할 수 있는 API가 없기 때문입니다.

문서에서는 이 상황을 악용할 수 있는 방법에 대해 설명하고 있기 때문에 이는 좋지 않은 상황입니다.

예를 들어 OpenSSL 라이브러리는 개인 키가 해방되기 전에 중요한 메모리 섹션을 덮어씁니다.Java는 가비지 컬렉션이기 때문에 키를 사용한 후 즉시 적용되는 Java 키의 개인 정보를 삭제하고 무효화하는 명시적인 방법이 필요합니다.

Jon Sket이 말했듯이, 반사를 이용하는 것 외에는 방법이 없다.

그러나 반성이 옵션인 경우 이 작업을 수행할 수 있습니다.

public static void main(String[] args) {
    System.out.println("please enter a password");
    // don't actually do this, this is an example only.
    Scanner in = new Scanner(System.in);
    String password = in.nextLine();
    usePassword(password);

    clearString(password);

    System.out.println("password: '" + password + "'");
}

private static void usePassword(String password) {

}

private static void clearString(String password) {
    try {
        Field value = String.class.getDeclaredField("value");
        value.setAccessible(true);
        char[] chars = (char[]) value.get(password);
        Arrays.fill(chars, '*');
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

실행 시

please enter a password
hello world
password: '***********'

주의: GC 사이클의 일부로 String의 char[]가 복사되어 있는 경우 이전 복사본이 메모리 어딘가에 있을 수 있습니다.

이 오래된 복사본은 힙 덤프에는 표시되지 않지만 프로세스의 원시 메모리에 직접 액세스할 수 있는 경우 확인할 수 있습니다.일반적으로 이러한 접근권을 가진 사람은 피해야 합니다.

이러한 이유로 비밀번호는 String이 아닌 char[] 배열을 선택해야 합니다.

1. Java에서는 String은 불변하기 때문에 패스워드를 플레인 텍스트로 저장하면 Garbage Collector가 패스워드를 클리어할 때까지 메모리에 사용할 수 있습니다.String은 재사용을 위해 String 풀에서 사용되기 때문에 장기간 메모리에 남아 있어 보안상의 위협이 됩니다.

메모리 덤프에 액세스 할 수 있는 사람은 누구나 클리어 텍스트로 패스워드를 찾을 수 있기 때문에 항상 일반 텍스트가 아닌 암호화된 패스워드를 사용해야 합니다.Strings는 불변하기 때문에 Strings의 내용은 변경할 수 없습니다.변경하면 새로운 String이 생성되기 때문입니다.한편 char[]를 사용하는 경우 모든 요소를 공백 또는 0으로 설정할 수 있습니다.따라서 암호를 문자 배열에 저장하면 암호를 도용하는 보안 위험을 확실히 줄일 수 있습니다.

2. Java 자체는 보안상의 이유를 나타내는 클리어 텍스트로 비밀번호를 반환하는 폐지된 getText() 메서드가 아닌 char[]를 반환하는 JPasswordField의 getPassword() 메서드를 사용할 것을 권장합니다.Java 팀의 조언을 따르고 표준을 따르지 않는 것이 좋습니다.

3. String을 사용하면 로그 파일이나 콘솔에 보통 텍스트가 인쇄될 위험이 항상 있지만 어레이를 사용하면 어레이의 내용은 인쇄되지 않고 메모리 위치가 인쇄됩니다.진짜 이유는 아니지만 그래도 말이 된다.

String strPassword="Unknown";
char[] charPassword= new char[]{'U','n','k','w','o','n'};
System.out.println("String password: " + strPassword);
System.out.println("Character password: " + charPassword);

String password: Unknown
Character password: [C@110b053

블로그에서 참조.이게 도움이 됐으면 좋겠어요.

편집: 1년간의 보안 조사 후 이 답변으로 돌아오면, 평문 비밀번호를 실제로 비교할 수 없다는 다소 유감스러운 의미가 있음을 알 수 있습니다.제발 하지마.소금과 적당한 횟수만큼 반복하여 안전한 단방향 해시를 사용합니다.도서관을 이용하는 것을 고려해보세요.이것들은 올바르게 하기 어렵습니다.

원답:String.equals()가 단락 평가를 사용하기 때문에 타이밍 공격에 취약하다는 사실은 어떻습니까?그럴 가능성은 낮지만 이론적으로는 올바른 문자 시퀀스를 판단하기 위해 비밀번호 비교 시간을 설정할 수 있습니다.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // Quits here if Strings are different lengths.
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // Quits here at first different character.
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

공격 타이밍에 관한 기타 자원:

char array는 사용 후 수동으로 청소하지 않는 한 vs String을 제공하는 것이 없습니다.실제로 그렇게 하는 사람은 본 적이 없습니다.그래서 저는 char[] vs String 선호도가 좀 과장된 것 같아요.

여기 Spring Security 라이브러리를 보고 자신에게 물어보세요. Spring Security의 사람들이 무능한지 아니면 char[]비밀번호가 별로 의미가 없는 것인지.어떤 악의적인 해커가 RAM의 메모리 덤프를 탈취할 경우, 비밀번호를 숨기는 정교한 방법을 사용하더라도 반드시 모든 비밀번호를 취득해야 합니다.

단, Java는 항상 변경되기 때문에 Java 8의 String Deduplication 기능과 같은 일부 무서운 기능으로 인해 String 객체가 사용자 모르게 삽입될 수 있습니다.하지만 그건 다른 얘기야

문자열은 불변하며 한 번 생성되면 변경할 수 없습니다.패스워드를 문자열로 작성하면 힙 또는 String 풀에 패스워드에 대한 잘못된 참조가 남습니다.Java 프로세스의 힙 덤프를 가져와 신중하게 스캔하면 암호를 추측할 수 있습니다.물론 사용되지 않는 문자열은 가비지가 수집되지만 이는 GC가 언제 시작하느냐에 따라 달라집니다.

다른 쪽 문자 []는 인증이 완료되는 즉시 모든 M 또는 백슬래시와 같은 임의의 문자로 덮어쓸 수 있습니다.다른 사용자가 힙 덤프를 사용하더라도 현재 사용되지 않는 암호를 얻지 못할 수 있습니다.이를 통해 GC가 오브젝트 콘텐츠를 실행하기를 기다리는 것과 마찬가지로 오브젝트 콘텐츠를 직접 클리어하는 것과 같은 의미로 보다 많은 제어를 할 수 있습니다.

문자열은 불변이며 문자열 풀로 이동합니다.한 번 쓰면 덮어쓸 수 없습니다.

char[]한 후 .이 배열은 다음과 같습니다.

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
 allowUser = true;
 cleanPassword(passw);
 cleanPassword(dbPassword);
 passw=null;
}

private static void cleanPassword (char[] pass) {

Arrays.fill(pass, '0');
}

공격자가 이를 사용할 수 있는 시나리오 중 하나는 크래시 덤프입니다. JVM이 크래시하여 메모리 덤프를 생성하면 암호를 볼 수 있습니다.

그것은 반드시 악의적인 외부 공격자는 아니다.이는 모니터링을 위해 서버에 액세스할 수 있는 지원 사용자일 수 있습니다.그는 크래시 덤프를 훔쳐보고 암호를 찾을 수 있었다.

은 '이기 때문입니다.char[]「 한 반면,String이치노

Strings자바어그렇기 때문에 한 번 작성하면 변경할 수 없기 때문에 내용물을 메모리에서 삭제할 수 있는 유일한 방법은 가비지를 수집하는 것입니다.오브젝트에 의해 해방된 메모리를 덮어쓸 수 있는 경우에만 데이터가 없어집니다.

이제 Java에서 가비지 컬렉션은 보장된 간격으로 발생하지 않습니다.String따라서 메모리 내에 장기간 남아 있을 수 있습니다.이 시간 동안 프로세스가 크래시되면 문자열의 내용이 메모리 덤프 또는 로그가 될 수 있습니다.

문자 배열에서는 암호를 읽고 가능한 한 빨리 작업을 마친 다음 내용을 즉시 변경할 수 있습니다.

Java ★★★★★★★★★★★★★★★★★★★★★★★★★」따라서 문자열이 생성될 때마다 가비지가 수집될 때까지 메모리에 남아 있습니다.따라서 메모리에 액세스할 수 있는 사람은 누구나 문자열 값을 읽을 수 있습니다.
문자열 값이 변경되면 새 문자열이 생성됩니다.따라서 원래 값과 수정된 값은 가비지가 수집될 때까지 메모리에 남아 있습니다.

문자 배열에서는 패스워드의 목적에 맞게 배열의 내용을 수정하거나 삭제할 수 있습니다.어레이를 수정한 후 가비지 컬렉션이 시작되기 전에도 어레이의 원래 내용을 메모리에서 찾을 수 없습니다.

보안상의 문제가 있으므로 비밀번호를 문자 배열로 저장하는 것이 좋습니다.

케이스 문자열:

    String password = "ill stay in StringPool after Death !!!";
    // some long code goes
    // ...Now I want to remove traces of password
    password = null;
    password = "";
    // above attempts wil change value of password
    // but the actual password can be traced from String pool through memory dump, if not garbage collected

대/소문자 배열:

    char[] passArray = {'p','a','s','s','w','o','r','d'};
    // some long code goes
    // ...Now I want to remove traces of password
    for (int i=0; i<passArray.length;i++){
        passArray[i] = 'x';
    }
    // Now you ACTUALLY DESTROYED traces of password form memory

String을 사용할지, Char[]를 사용할지는 둘 다 장단점이 있기 때문에 논란의 여지가 있습니다.사용자가 무엇을 필요로 하는지에 따라 다릅니다.

Java의 문자열은 불변하기 때문에 문자열을 조작하려고 할 때마다 새 개체가 생성되고 기존 문자열은 영향을 받지 않습니다.이는 패스워드를 String으로 저장하는 장점이라고 볼 수 있지만 오브젝트는 사용 후에도 메모리에 남아 있습니다.따라서 어떤 방법으로든 오브젝트의 메모리 위치를 알게 되면 그 위치에 저장된 비밀번호를 쉽게 추적할 수 있습니다.

Char[]는 가변이지만 사용 후 프로그래머가 어레이를 명시적으로 클리닝하거나 값을 덮어쓸 수 있다는 장점이 있습니다.따라서 사용이 완료되면 데이터가 지워지고 저장된 정보에 대해 아무도 알 수 없게 됩니다.

위의 상황에 따라 String으로 할지 Char[]로 할지 판단할 수 있습니다.

위에 훌륭한 답변들이 많이 있습니다.제가 추측하고 있는 다른 점이 있습니다(틀렸다면 정정해 주세요).기본적으로는 Java는 문자열 저장에 UTF-16을 사용합니다.문자 배열 char[]array를 사용하면 유니코드, 지역 문자 등을 쉽게 사용할 수 있습니다.이 기술을 사용하면 모든 문자 세트가 패스워드를 저장하기 위해 동등하게 존중되므로 문자 집합의 혼란으로 인해 특정 암호 문제가 발생하지 않습니다.마지막으로 char 배열을 사용하여 비밀번호 배열을 원하는 문자 집합 문자열로 변환할 수 있습니다.

언급URL : https://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords