차이 - stringbuilder string java




char[]가 String보다 String에 비해 선호되는 이유는 무엇입니까? (12)

  1. 문자열은 암호를 일반 텍스트로 저장하면 가비지 컬렉터가이를 지울 때까지 Java에서 변경 되지 않으며 String이 재사용을 위해 String 풀에서 사용되기 때문에 오래 동안 메모리에 남아있을 가능성이 상당히 높습니다 기간은 보안 위협이됩니다. 메모리 덤프에 액세스 권한이있는 사용자는 암호를 일반 텍스트로 찾을 수 있기 때문에
  2. char []를 반환하는 JPasswordField의 getPassword() 메소드와 보안상의 이유로 일반 텍스트로 암호를 반환하는 getText() 메소드를 사용하는 Java 권장 사항 .
  3. toString () 항상 로그 파일이나 콘솔에 일반 텍스트를 인쇄 할 위험이 있지만 Array를 사용하면 메모리 위치가 인쇄되는 대신 배열 내용을 인쇄하지 않습니다.

    String strPwd = "passwd";
    char[] charPwd = new char[]{'p','a','s','s','w','d'};
    System.out.println("String password: " + strPwd );
    System.out.println("Character password: " + charPwd );
    

    문자열 암호 : passwd

    문자 암호 : [C @ 110b2345

최종 생각 : char []를 사용하는 것만으로는 충분하지 않지만 더 안전하게하기 위해 내용을 지울 필요가 있습니다. 또한 일반 텍스트 대신 해쉬 된 또는 암호화 된 암호로 작업하고 인증이 완료되면 바로 메모리에서 지우는 것이 좋습니다.

Swing에서 암호 필드는 일반적인 getText() ( String 반환합니다) 메서드 대신 getPassword() ( char[] ) 메서드를 반환합니다. 마찬가지로 String 을 사용하여 암호를 처리하지 않도록 제안했습니다.

String 은 암호와 관련하여 보안에 위협이되는 이유는 무엇입니까? char[] 를 사용하는 것이 불편합니다.


Jon Skeet이 말했듯이, 리플렉션을 사용하는 것 외에는 다른 방법은 없습니다.

그러나 반사가 당신을위한 옵션이라면, 당신은 이것을 할 수 있습니다.

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: '***********'

참고 : String의 char []가 GC주기의 일부로 복사 된 경우 이전 사본이 메모리의 어딘가에있을 가능성이 있습니다.

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


공식 문서를 인용하자면 자바 암호화 아키텍쳐 가이드char[]String 패스워드 (패스워드 기반 암호화에 대해서 말하고 있지만 이것은 일반적으로 패스워드에 관한 것이다)

java.lang.String 유형의 오브젝트에 암호를 수집하여 저장하는 것은 논리적 인 것처럼 보입니다. 그러나 여기에주의해야 할 사항이 있습니다. String 유형의 Object 는 변경 불가능합니다. 즉, 사용 후 String 내용을 변경 (덮어 쓰기)하거나 0으로 설정할 수있는 메서드가 정의되어 있지 않습니다. 이 기능은 String 객체가 사용자 비밀번호와 같은 보안에 민감한 정보를 저장하는 데 적합하지 않게합니다. 항상 보안에 민감한 정보를 char 배열로 저장하고 저장해야합니다.

Java 프로그래밍 언어, 버전 4.0에 대한 보안 코딩 지침의 가이드 라인 2-2 도 비슷한 내용을 말합니다 (원래는 로깅의 맥락입니다).

지침 2-2 : 매우 민감한 정보를 기록하지 마십시오.

사회 보장 번호 (SSN) 및 암호와 같은 일부 정보는 매우 민감합니다. 이 정보는 필요 이상으로 오래 보관하거나 관리자가 볼 수있는 위치에 보관해서는 안됩니다. 예를 들어, 로그 파일로 전송해서는 안되며 검색을 통해 그 존재를 탐지 할 수 없습니다. 일부 임시 데이터는 문자 배열과 같은 변경 가능한 데이터 구조에 보관 될 수 있으며 사용 직후에 지워집니다. 객체가 메모리에서 프로그래머에게 투명하게 이동되므로 데이터 구조를 지우면 일반 Java 런타임 시스템의 효율성이 감소합니다.

이 가이드 라인은 또한 다루고있는 데이터의 의미 론적 지식을 가지고 있지 않은 하위 레벨 라이브러리의 구현 및 사용에 영향을 미칩니다. 예를 들어, 저수준의 스트링 파싱 라이브러리는 그것이 작동하는 텍스트를 로그 할 수있다. 응용 프로그램은 SSN을 라이브러리와 구문 분석 할 수 있습니다. 이렇게하면 관리자가 SSN을 로그 파일에 액세스 할 수있는 상황이 만들어집니다.


나는 이것이 유효한 제안이라고 생각하지 않지만, 적어도 나는 이유에서 추측 할 수있다.

나는 동기 부여가 사용 된 후 즉시 비밀 번호의 모든 흔적을 확실하고 확실하게 지울 수 있기를 바랍니다. char[] 를 사용하면 배열의 각 요소를 공백으로 덮어 쓸 수 있습니다. 그런 식으로 String 의 내부 값을 편집 할 수 없습니다.

그러나 그것은 홀로 좋은 대답은 아닙니다. char[] 또는 String 대한 참조가 이스케이프되지 않았는지 확인하십시오. 그러면 보안 문제는 없습니다. 그러나 그 문제는 String 객체가 이론적으로 intern() 될 수 있고 상수 풀 내부에서 살아남을 수 있다는 것입니다. 나는 char[] 사용하는 것이 이러한 가능성을 금지한다고 생각한다.


대답은 이미 주어졌지만 최근에 자바 표준 라이브러리에서 발견 한 문제를 알려 드리고자합니다. 암호 문자열을 어디에서나 char[] 로 대체하는 것은 매우 중요하지만 다른 중요한 보안 데이터는 메모리에서 지우는 데 간과되는 것처럼 보입니다.

나는 PrivateKey 클래스를 생각하고있다. PKCS # 12 파일에서 개인 RSA 키를로드하여 일부 작업을 수행하는 시나리오를 생각해보십시오. 이제이 경우 비밀번호 만 스니핑하면 키 파일에 대한 물리적 액세스가 적절하게 제한되는 한 많은 도움이되지 않습니다. 공격자라면 암호 대신 직접 키를 얻는 것이 훨씬 나을 것입니다. 원하는 정보가 매니 폴드, 코어 덤프, 디버거 세션 또는 스왑 파일로 유출 될 수 있습니다.

그리고 그것이 나오면, 해당 정보를 구성하는 바이트를 지울 수있는 API가 없으므로 메모리에서 PrivateKey 의 개인 정보를 지울 수있는 방법은 없습니다.

paper 는이 상황이 어떻게 잠재적으로 악용 될 수 있는지를 설명하기 때문에 나쁜 상황입니다.

예를 들어 OpenSSL 라이브러리는 개인 키가 해제되기 전에 중요한 메모리 섹션을 덮어 씁니다. Java는 가비지 콜렉션이므로, 키를 사용한 직후에 적용될 Java 키의 개인 정보를 지우고 무효화하는 명시적인 메소드가 필요합니다.


문자 배열 ( char[] )은 사용 후 각 문자를 0으로 설정하고 문자열을 지우지 않고 지울 수 있습니다. 누군가가 어떻게 든 메모리 이미지를 볼 수 있다면 문자열을 사용하면 일반 텍스트로 암호를 볼 수 있지만 char[] 를 사용하면 0으로 데이터를 제거한 후 암호가 안전합니다.


이것들은 모두 이유입니다. 패스워드에는 String 대신에 char [] 배열을 선택해야합니다.

1. 패스워드를 일반 텍스트로 저장하면 문자열은 Java에서 불변하므로 가비지 컬렉터가이를 지울 때까지 메모리에서 사용할 수 있고 문자열은 재사용을 위해 String 풀에서 사용되기 때문에 오래 동안 메모리에 남아있을 가능성이 상당히 높습니다 기간은 보안 위협이됩니다. 메모리 덤프에 액세스 할 수있는 사람은 일반 텍스트로 암호를 찾을 수 있기 때문에 일반 텍스트보다 항상 암호화 된 암호를 사용해야하는 또 다른 이유입니다. 문자열은 변경되지 않기 때문에 문자열의 내용을 변경할 수있는 방법은 없습니다. 변경으로 인해 새로운 String이 생성되고 char []를 사용하면 요소를 모두 공백 또는 0으로 설정할 수 있습니다. 따라서 문자 배열에 암호를 저장하면 암호를 도용하는 보안 위험이 분명히 완화됩니다.

2. 자바 자체는 char []를 반환하는 JPasswordField의 getPassword () 메소드와 보안상의 이유로 clear 텍스트로 패스워드를 반환하는 getText () 메소드를 사용하는 것을 권장한다. Java 팀의 조언을 따르고 그에 맞서는 것이 아니라 표준을 준수하는 것이 좋습니다.

3. 문자열을 사용하면 로그 파일이나 콘솔에 일반 텍스트를 인쇄 할 위험이 항상 있습니다. 그러나 Array를 사용하면 메모리 내용이 인쇄되는 대신 배열 내용을 인쇄하지 않습니다. 진정한 이유는 아니지만 여전히 의미가 있습니다.

    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: [[email protected]

참조 : http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html 희망이 도움이됩니다.


문자열은 변경할 수 없습니다 . 즉 일단 String 생성하면 다른 프로세스가 메모리를 덤프 할 수있는 경우 reflection 제외하고는 가비지 수집이 시작되기 전에 데이터를 제거 할 수 없습니다.

배열을 사용하여 작업을 완료 한 후에 명시 적으로 데이터를 지울 수 있습니다. 배열을 원하는대로 덮어 쓸 수 있으며 암호는 가비지 수집 전이라도 시스템의 어느 곳에도 존재하지 않습니다.

그렇습니다. 이것은 보안 문제입니다.하지만 char[] 사용해도 공격자의 기회 창은 줄어들며이 특정 유형의 공격에만 해당됩니다.

주석에서 언급했듯이, 가비지 컬렉터가 배열을 이동하면 데이터가 메모리에 누락 될 수 있습니다. 이것은 구현에 따라 다르다고 생각합니다. 가비지 수집기 이러한 상황을 피하기 위해 모든 메모리를 지울 수 있습니다 . 그것이 실제로 발생하더라도 char[] 에 실제 문자가 공격 창으로 포함 된 시간은 여전히 ​​있습니다.


1) 암호를 일반 텍스트로 저장하면 문자열이 Java에서 불변하므로 가비지 수집기가 암호를 지울 때까지 메모리에서 사용할 수 있고 문자열은 재사용을 위해 문자열 풀에서 사용되기 때문에 메모리에 남아있을 가능성이 상당히 높습니다 장기간 동안 보안 위협이됩니다. 메모리 덤프에 액세스 할 수있는 사람은 일반 텍스트로 암호를 찾을 수 있기 때문에 일반 텍스트보다 항상 암호화 된 암호를 사용해야하는 또 다른 이유입니다. 문자열은 불변이므로, String이 변경 될 수있는 방법은 없습니다. 왜냐하면 변경으로 인해 새로운 String이 생성 될 것이고, char [] 일 경우에는 모든 요소를 ​​공백이나 0으로 설정할 수 있습니다. 따라서 문자 배열에 암호를 저장하면 암호를 도용 할 때 보안 위험이 줄어 듭니다.

2) Java 자체는 char []를 반환하는 JPasswordField의 getPassword () 메소드와 보안 이유를 나타내는 일반 텍스트로 패스워드를 반환하는 getText () 메소드를 사용하는 것을 권장한다. Java 팀의 조언을 따르고 반대하는 것이 아니라 표준을 준수하는 것이 좋습니다.


java의 문자열은 변경 불가능합니다. 따라서 문자열이 생성 될 때마다 가비지 수집 될 때까지 메모리에 남아 있습니다. 따라서 메모리에 액세스하는 모든 사용자는 문자열의 값을 읽을 수 있습니다.
문자열의 값이 수정되면 새로운 문자열이 생성됩니다. 따라서 원래 값과 수정 된 값은 가비지 수집 될 때까지 메모리에 남아 있습니다.

문자 배열을 사용하면 암호의 용도가 정해지면 배열의 내용을 수정하거나 지울 수 있습니다. 어레이의 원래 내용은 가비지 콜렉션이 수정되기 전에 메모리에서 발견되지 않습니다.

보안상의 이유로 문자 배열로 암호를 저장하는 것이 좋습니다.


문자열은 변경할 수 없으며 일단 만들어지면 변경할 수 없습니다. 암호로 문자열을 만들면 힙이나 문자열 풀에 대한 암호에 대한 참조가 누락됩니다. 이제 누군가가 Java 프로세스의 힙 덤프를 가져 와서주의 깊게 스캔하면 암호를 추측 할 수 있습니다. 물론 이러한 사용되지 않은 문자열은 가비지 수집되지만 GC가 실행되는시기에 따라 다릅니다.

다른 쪽에서는 char []가 인증이 완료 되 자마자 변경 가능합니다. 모든 M이나 백 슬래시와 같은 문자로 덮어 쓸 수 있습니다. 이제 누군가 힙 덤프를 걸더라도 현재 사용되지 않는 암호를 얻을 수 없을 수도 있습니다. 이렇게하면 GC가 수행하기를 기다리는 것과 비교하여 Object 내용을 지우는 것과 같은 의미에서 더 많은 제어가 가능합니다.


짧고 솔직한 대답은 객체가없는 char[]동안 변경 될 수 있기 때문 입니다 String.

Strings자바에서 불변 개체입니다. 그래서 일단 생성 된 후에는 수정할 수 없으므로 내용을 메모리에서 제거하는 유일한 방법은 가비지 수집하는 것입니다. 그러면 객체에 의해 해제 된 메모리를 덮어 쓸 수 있고 데이터가 사라지게됩니다.

Java에서 가비지 콜렉션은 보장 된 간격으로 발생하지 않습니다. 는 String이렇게 오랜 시간 동안 메모리에 유지 수 있으며, 프로세스가이 시간 동안 충돌하는 경우, 문자열의 내용이 메모리 덤프 또는 일부 로그에 끝낼 수 있습니다.

문자 배열을 사용하면 암호를 읽고 최대한 빨리 작업을 완료 한 다음 즉시 내용을 변경할 수 있습니다.





char