setAccessible을 "합법적 인"용도로만 제한하는 방법은 무엇입니까?


100

의 힘에 대해 더 많이 배울수록 java.lang.reflect.AccessibleObject.setAccessible그것이 무엇을 할 수 있는지에 대해 더욱 놀랐습니다. 이것은 질문에 대한 내 대답에서 수정되었습니다 ( 반영을 사용하여 단위 테스트를 위해 정적 최종 File.separatorChar 변경 ).

import java.lang.reflect.*;

public class EverythingIsTrue {
   static void setFinalStatic(Field field, Object newValue) throws Exception {
      field.setAccessible(true);

      Field modifiersField = Field.class.getDeclaredField("modifiers");
      modifiersField.setAccessible(true);
      modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

      field.set(null, newValue);
   }
   public static void main(String args[]) throws Exception {      
      setFinalStatic(Boolean.class.getField("FALSE"), true);

      System.out.format("Everything is %s", false); // "Everything is true"
   }
}

정말 터무니없는 일을 할 수 있습니다.

public class UltimateAnswerToEverything {
   static Integer[] ultimateAnswer() {
      Integer[] ret = new Integer[256];
      java.util.Arrays.fill(ret, 42);
      return ret;
   }   
   public static void main(String args[]) throws Exception {
      EverythingIsTrue.setFinalStatic(
         Class.forName("java.lang.Integer$IntegerCache")
            .getDeclaredField("cache"),
         ultimateAnswer()
      );
      System.out.format("6 * 9 = %d", 6 * 9); // "6 * 9 = 42"
   }
}

아마도 API 설계자는 남용이 얼마나 될 setAccessible수 있는지 알고 있지만이를 제공하기 위해 합법적 인 용도가 있다는 것을 인정했을 것입니다. 그래서 내 질문은 다음과 같습니다.

  • 진정으로 합법적 인 용도는 setAccessible무엇입니까?
    • Java가 애초에 이러한 필요성을 갖지 않도록 설계되었을 수 있습니까?
    • 그러한 설계의 부정적인 결과 (있는 경우)는 무엇입니까?
  • setAccessible합법적 인 용도로만 제한 할 수 있습니까 ?
    • 그것은 통해서만 SecurityManager입니까?
      • 어떻게 작동합니까? 화이트리스트 / 블랙리스트, 세분성 등?
      • 응용 프로그램에서 구성해야하는 것이 일반적입니까?
    • 구성에 setAccessible관계없이 내 클래스를 증명할 수 있도록 작성할 수 있습니까 SecurityManager?
      • 아니면 구성을 관리하는 사람의 자비입니까?

한 가지 더 중요한 질문은 다음과 같습니다.이 문제에 대해 걱정해야합니까 ???

내 수업 중 누구도 강제적 인 개인 정보 보호와 같은 모습을 보이지 않습니다. 싱글 톤 패턴 (장점에 대한 의문을 제쳐두고)은 이제 시행이 불가능합니다. 위의 스 니펫에서 볼 수 있듯이 Java 기본 작동 방식에 대한 몇 가지 기본적인 가정조차도 보장되지 않습니다.

이 문제는 진짜가 아닌가 ???


좋아, 난 그냥 확인 : 덕분에 setAccessible, 자바 문자열은 하지 불변.

import java.lang.reflect.*;

public class MutableStrings {
   static void mutate(String s) throws Exception {
      Field value = String.class.getDeclaredField("value");
      value.setAccessible(true);
      value.set(s, s.toUpperCase().toCharArray());
   }   
   public static void main(String args[]) throws Exception {
      final String s = "Hello world!";
      System.out.println(s); // "Hello world!"
      mutate(s);
      System.out.println(s); // "HELLO WORLD!"
   }
}

이것이 큰 관심사라고 생각하는 유일한 사람입니까?


30
그들이 C ++로 무엇을 할 수 있는지 봐야합니다! (아, 그리고 아마 C #.)
톰 Hawtin의 - tackline

답변:


105

이것에 대해 걱정할 필요가 있습니까 ???

그것은 전적으로 어떤 유형의 프로그램을 작성하고 어떤 종류의 아키텍처에 따라 달라집니다.

foo.jar라는 소프트웨어 구성 요소를 전 세계 사람들에게 배포한다면 어쨌든 완전히 자비를 베푸는 것입니다. .jar 내부의 클래스 정의를 수정할 수 있습니다 (리버스 엔지니어링 또는 직접 바이트 코드 조작을 통해). 그들은 자신의 JVM 등에서 당신의 코드를 실행할 수 있습니다.

HTTP를 통해 사람 및 시스템과 만 인터페이스하는 웹 애플리케이션을 작성하고 애플리케이션 서버를 제어하는 ​​경우에도 문제가되지 않습니다. 물론 회사의 동료 코더는 싱글 톤 패턴을 깨는 코드를 만들 수 있지만 실제로 원하는 경우에만 가능합니다.

미래의 직업이 Sun Microsystems / Oracle에서 코드를 작성하고 Java 코어 또는 기타 신뢰할 수있는 구성 요소에 대한 코드를 작성해야하는 경우이 점을 알아야합니다. 그러나 걱정하면 머리카락이 빠지게됩니다. 어쨌든 그들은 내부 문서와 함께 보안 코딩 지침 을 읽도록 만들 것입니다 .

Java 애플릿을 작성하려는 경우 보안 프레임 워크를 알고 있어야합니다. setAccessible을 호출하려는 서명되지 않은 애플릿은 SecurityException을 발생시킵니다.

setAccessible은 기존의 무결성 검사를 처리하는 유일한 방법이 아닙니다. 직접 메모리에 액세스하는 것을 포함하여 원하는 모든 작업을 수행 할 수있는 sun.misc.Unsafe라는 비 API 핵심 Java 클래스가 있습니다. 네이티브 코드 (JNI)도 이러한 종류의 제어를 우회 할 수 있습니다.

샌드 박스 환경 (예 : Java Applets, JavaFX)에서 각 클래스에는 권한 집합이 있으며 안전하지 않은 setAccessible에 대한 액세스 권한과 기본 구현 정의는 SecurityManager에 의해 제어됩니다.

"Java 액세스 수정자는 보안 메커니즘이 아닙니다."

이는 Java 코드가 실행되는 위치에 따라 크게 달라집니다. 핵심 Java 클래스는 액세스 수정자를 보안 메커니즘으로 사용하여 샌드 박스를 적용합니다.

setAccessible의 진정한 합법적 인 용도는 무엇입니까?

Java 코어 클래스는 보안상의 이유로 비공개로 유지되어야하는 항목에 쉽게 액세스 할 수있는 방법으로이를 사용합니다. 예를 들어 Java Serialization 프레임 워크는이를 사용하여 객체를 deserialize 할 때 개인 객체 생성자를 호출합니다. 누군가 System.setErr을 언급했는데 좋은 예가 될 수 있지만 흥미롭게도 System 클래스 메소드 setOut / setErr / setIn은 모두 최종 필드의 값을 설정하기 위해 네이티브 코드를 사용합니다.

또 다른 명백한 합법적 사용은 개체 내부를 들여다 볼 필요가있는 프레임 워크 (지속성, 웹 프레임 워크, 주입)입니다.

제 생각에는 디버거는 일반적으로 동일한 JVM 프로세스에서 실행되지 않고 대신 다른 수단 (JPDA)을 사용하는 JVM과의 인터페이스이므로이 범주에 속하지 않습니다.

Java가 애초에 이러한 필요성을 갖지 않도록 설계되었을 수 있습니까?

잘 대답하기에는 꽤 깊은 질문입니다. 그렇다고 생각하지만 그다지 선호되지 않는 다른 메커니즘을 추가해야합니다.

setAccessible을 합법적 인 용도로만 제한 할 수 있습니까?

적용 할 수있는 가장 간단한 OOTB 제한은 SecurityManager를 갖고 특정 소스에서 오는 코드에만 setAccessible을 허용하는 것입니다. 이것은 Java가 이미하는 일입니다. JAVA_HOME에서 오는 표준 Java 클래스는 setAccessible을 수행 할 수 있지만 foo.com의 서명되지 않은 애플릿 클래스는 setAccessible을 수행 할 수 없습니다. 이전에 말했듯이이 권한은 둘 중 하나가 있든 없든 이진입니다. setAccessible이 특정 필드 / 메서드를 수정하고 다른 필드는 허용하지 않도록 허용하는 명백한 방법이 없습니다. 그러나 SecurityManager를 사용하면 리플렉션을 사용하거나 사용하지 않고 클래스가 특정 패키지를 완전히 참조하지 못하도록 할 수 있습니다.

SecurityManager 구성에 관계없이 내 클래스를 setAccessible-proof로 작성할 수 있습니까? ... 아니면 구성을 관리하는 사람의 자비에 있습니까?

당신은 할 수 없으며 가장 확실합니다.


"만약 당신이 foo.jar라는 소프트웨어 컴포넌트를 전세계 사람들에게 배포한다면, 당신은 어쨌든 그들의 자비에 달려 있습니다. 그들은 리버스 엔지니어링이나 직접적인 바이트 코드 조작을 통해 당신의 .jar 안의 클래스 정의를 수정할 수 있습니다. 자신의 JVM 등에서 코드를 실행할 수 있습니다.이 경우 걱정할 필요가 없습니다. " 이것이 여전히 사실입니까? 소프트웨어 변조를 더 어렵게 만드는 것에 대한 조언이 있습니까? 이 때문에 자바 데스크톱 애플리케이션을 창 밖으로 버리는 것은 어렵습니다.
Sero

@naaz 나는 아무것도 변하지 않았다고 말해야 할 것입니다. 아키텍처가 당신에게 불리하게 작용하고 있다는 것입니다. 내가 완전히 제어 할 수있는 내 컴퓨터에서 실행되는 소프트웨어는 변경할 수 있습니다. 가장 강력한 억지력은 합법적 일 수 있지만 모든 시나리오에서 효과가있을 것이라고는 생각하지 않습니다. Java 바이너리가 가장 쉽게 되돌릴 수 있다고 생각하지만 경험이있는 사람은 무엇이든 조작 할 수 있습니다. 난독 화는 큰 변경을 어렵게하여 도움이되지만, 어떤 종류의 부울 (저작권 검사와 같은)도 여전히 우회하기가 쉽습니다. 대신 서버에 핵심 부품을 배치 할 수 있습니다.
Sami Koivu

denuvo는 어떻습니까?
Sero

15
  • 진정으로 합법적 인 용도는 setAccessible무엇입니까?

단위 테스트, JVM 내부 (예 : 구현 System.setError(...)) 등.

  • Java가 애초에 이러한 필요성을 갖지 않도록 설계되었을 수 있습니까?
  • 그러한 설계의 부정적인 결과 (있는 경우)는 무엇입니까?

많은 것들이 구현 불가능할 것입니다. 예를 들어 다양한 Java 지속성, 직렬화 및 종속성 주입은 리플렉션에 의존합니다. 그리고 런타임에 JavaBeans 규칙에 의존하는 거의 모든 것.

  • setAccessible합법적 인 용도로만 제한 할 수 있습니까 ?
  • 그것은 통해서만 SecurityManager입니까?

예.

  • 어떻게 작동합니까? 화이트리스트 / 블랙리스트, 세분성 등?

권한에 따라 다르지만 사용 권한 setAccessible은 바이너리 라고 생각합니다 . 세분성을 원하는 경우 제한하려는 클래스에 대해 다른 보안 관리자와 함께 다른 클래스 로더를 사용해야합니다. 세분화 된 논리를 구현하는 사용자 지정 보안 관리자를 구현할 수 있다고 생각합니다.

  • 응용 프로그램에서 구성해야하는 것이 일반적입니까?

아니.

  • 내 수업을 다음에 setAccessible관계없이 증명할 수 있도록 작성할 수 있습니까?SecurityManager구성에 ?
    • 아니면 구성을 관리하는 사람의 자비입니까?

아니, 당신은 할 수 없습니다.

다른 대안은 소스 코드 분석 도구를 통해이를 "시행"하는 것입니다. 예 : 사용자 정의 pmd또는 findbugs규칙. 또는 (말)로 식별되는 코드의 선택적 코드 검토 grep setAccessible ....

후속 조치에 대한 응답으로

내 수업 중 어느 것도 강제적 인 개인 정보 보호와 같은 모양을 가지고 있지 않습니다. 싱글 톤 패턴 (장점에 대한 의문을 제쳐두고)은 이제 시행이 불가능합니다.

그게 걱정된다면 걱정해야 할 것 같습니다. 하지만 정말로 당신은 강제로 다른 프로그래머가 디자인 결정을 존중 . 사람들이 리플렉션을 사용하여 무상으로 여러 개의 싱글 톤 인스턴스를 생성 할만큼 어리 석다면 (예를 들어) 결과를 감수 할 수 있습니다.

반면에 민감한 정보가 공개되지 않도록 보호하는 의미를 포함하는 "개인 정보 보호"를 의미하는 경우 잘못된 트리를 짖는 것입니다. Java 애플리케이션에서 민감한 데이터를 보호하는 방법은 민감한 데이터를 처리하는 보안 샌드 박스에 신뢰할 수없는 코드를 허용하지 않는 것입니다. Java 액세스 수정자는 보안 메커니즘이 아닙니다.

<문자열 예>-이것이 큰 관심사라고 생각하는 유일한 사람입니까?

아마도 유일한 것은 아닙니다 :-). 그러나 IMO, 이것은 문제가 아닙니다. 신뢰할 수없는 코드는 샌드 박스에서 실행되어야한다는 사실은 인정됩니다. 이와 같은 일을하는 신뢰할 수있는 코드 / 신뢰할 수있는 프로그래머가 있으면 문제가 예기치 않게 변경 가능한 문자열보다 더 나쁩니다. (논리 폭탄, 은밀한 채널을 통한 데이터 유출을 생각하십시오. )

개발 또는 운영 팀에서 "나쁜 행위자"의 문제를 처리 (또는 완화)하는 방법이 있습니다. 그러나 비용이 많이 들고 제한적이며 대부분의 사용 사례에서 과도합니다.


1
지속성 구현과 같은 것들에도 유용합니다. 반사는 디버거에 실제로 유용하지 않습니다 (원래 의도 되었음에도 불구하고). 당신 SecurityManager이 얻을 수있는 모든 것은 권한 검사이기 때문에 유용하게 (서브 클래스) 변경할 수 없습니다. 정말로 할 수있는 것은 acc를보고 아마도 현재 스레드를 확인하는 스택을 걷는 것입니다). grep java.lang.reflect.
Tom Hawtin-tackline

@Stephen C : 이미 +1했지만 방금 추가 한 한 가지 질문에 대한 귀하의 의견도 감사드립니다. 미리 감사드립니다.
polygenelubricants 2010 년

grep은 끔찍한 아이디어입니다. Java에서 코드를 동적으로 실행하는 방법은 너무 많아서 거의 놓칠 수 있습니다. 일반적으로 블랙리스트 코드는 실패를위한 레시피입니다.
Antimony

"Java 액세스 수정자는 보안 메커니즘이 아닙니다." -실제로 그렇습니다. Java는 신뢰할 수있는 코드와 신뢰할 수없는 코드가 동일한 가상 머신에 공존 할 수 있도록 설계되었습니다. 이것은 처음부터 핵심 요구 사항의 일부였습니다. 그러나 시스템이 잠겨있는 SecurityManager로 실행되는 경우에만. 코드 샌드 박스 기능은 전적으로 액세스 지정자의 적용에 달려 있습니다.
Jules

@Jules-대부분의 Java 전문가는 이에 동의하지 않습니다. 예 : stackoverflow.com/questions/9201603/...
스티븐 C

11

반사는 실제로 이러한 관점에서 안전 / 보안과 직교합니다.

반사를 어떻게 제한 할 수 있습니까?

Java에는 보안 관리자 ClassLoader가 있으며 보안 모델의 기반이됩니다. 귀하의 경우에는 java.lang.reflect.ReflectPermission.

그러나 이것은 반성의 문제를 완전히 해결하지 못합니다. 사용 가능한 반사 기능은 현재는 그렇지 않은 세분화 된 권한 부여 체계의 적용을 받아야합니다. 예를 들어 특정 프레임 워크가 리플렉션 (예 : Hibernate)을 사용하도록 허용하지만 나머지 코드는 사용하지 않습니다. 또는 디버깅 목적으로 프로그램이 읽기 전용 방식으로 만 반영하도록 허용합니다.

미래에 주류가 될 수있는 한 가지 접근 방식 은 클래스에서 반사 기능을 분리하기 위해 소위 미러 를 사용하는 것입니다 . 미러 : 메타 레벨 시설의 설계 원칙을 참조하십시오 . 그러나이 문제를 다루는 다양한 다른 연구 가 있습니다. 그러나 나는 정적 언어보다 동적 언어에서 문제가 더 심각하다는 데 동의합니다.

반사가 우리에게주는 초능력에 대해 걱정해야합니까? 예, 아니오.

, Java 플랫폼이 Classloader보안 관리자 와 함께 보호되어야한다는 점에서 그렇습니다 . 반사를 망칠 수있는 능력은 위반으로 볼 수 있습니다.

아니 의미에서 대부분의 시스템 어쨌든 것을 완전히 확보하지. 많은 클래스가 자주 하위 클래스 화 될 수 있으며 잠재적으로 이미 시스템을 남용 할 수 있습니다. 물론 수업을 만들 final거나 봉인 할 수 있습니다. 하여 다른 jar에서 하위 클래스를 만들 수 없습니다. 그러나 이에 따라 올바르게 보호되는 클래스는 거의 없습니다 (예 : String).

이것 좀 봐 좋은 설명 은 최종 수업에 대한 답변을 . Sami Koivu 의 블로그 참조보안 관련 자바 해킹에 대한 자세한 내용 .

Java의 보안 모델은 어떤면에서는 불충분하다고 볼 수 있습니다. 다음과 같은 일부 언어NewSpeak 모듈성에 대해 훨씬 더 급진적 인 접근 방식을 취합니다. 여기서 종속성 반전 (기본적으로 아무것도 없음)에 의해 명시 적으로 제공되는 항목에만 액세스 할 수 있습니다.

어쨌든 보안이 중요하다는 점에 유의하는 것도 중요합니다. 상대적 . 예를 들어 언어 수준에서 모듈 양식이 CPU를 100 % 사용하거나 OutOfMemoryException. 그러한 우려는 다른 방법으로 해결해야합니다. 우리는 향후 Java가 리소스 사용 할당량으로 확장되는 것을 볼 수 있지만 내일은 아닙니다. :)

나는 주제에 대해 더 확장 할 수 있지만, 내 주장을 내린 것 같다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.