의 힘에 대해 더 많이 배울수록 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!"
}
}
이것이 큰 관심사라고 생각하는 유일한 사람입니까?
답변
이것에 대해 걱정할 필요가 있습니까 ???
그것은 전적으로 어떤 유형의 프로그램을 작성하고 어떤 종류의 아키텍처에 따라 달라집니다.
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로 작성할 수 있습니까? … 아니면 구성을 관리하는 사람의 자비에 있습니까?
당신은 할 수 없으며 가장 확실합니다.
답변
- 진정으로 합법적 인 용도는
setAccessible
무엇입니까?
단위 테스트, JVM 내부 (예 : 구현 System.setError(...)
) 등.
- Java가 애초에 이러한 필요성을 갖지 않도록 설계되었을 수 있습니까?
- 그러한 설계의 부정적인 결과 (있는 경우)는 무엇입니까?
많은 것들이 구현 불가능할 것입니다. 예를 들어 다양한 Java 지속성, 직렬화 및 종속성 주입은 리플렉션에 의존합니다. 그리고 런타임에 JavaBeans 규칙에 의존하는 거의 모든 것.
setAccessible
합법적 인 용도로만 제한 할 수 있습니까 ?- 그것은 통해서만
SecurityManager
입니까?
예.
- 어떻게 작동합니까? 화이트리스트 / 블랙리스트, 세분성 등?
권한에 따라 다르지만 사용 권한 setAccessible
은 바이너리 라고 생각합니다 . 세분성을 원하는 경우 제한하려는 클래스에 대해 다른 보안 관리자와 함께 다른 클래스 로더를 사용해야합니다. 세분화 된 논리를 구현하는 사용자 지정 보안 관리자를 구현할 수 있다고 생각합니다.
- 응용 프로그램에서 구성해야하는 것이 일반적입니까?
아니.
- 내 수업을 다음에
setAccessible
관계없이 증명할 수 있도록 작성할 수 있습니까?SecurityManager
구성에 ?
- 아니면 구성을 관리하는 사람의 자비입니까?
아니, 당신은 할 수 없습니다.
다른 대안은 소스 코드 분석 도구를 통해이를 “시행”하는 것입니다. 예 : 사용자 정의 pmd
또는 findbugs
규칙. 또는 (말)로 식별되는 코드의 선택적 코드 검토 grep setAccessible ...
.
후속 조치에 대한 응답으로
내 수업 중 어느 것도 강제적 인 개인 정보 보호와 같은 모양을 가지고 있지 않습니다. 싱글 톤 패턴 (장점에 대한 의문을 제쳐두고)은 이제 시행이 불가능합니다.
그게 걱정된다면 걱정해야 할 것 같습니다. 하지만 정말로 당신은 강제로 다른 프로그래머가 디자인 결정을 존중 . 사람들이 리플렉션을 사용하여 무상으로 여러 개의 싱글 톤 인스턴스를 생성 할만큼 어리 석다면 (예를 들어) 결과를 감수 할 수 있습니다.
반면에 민감한 정보가 공개되지 않도록 보호하는 의미를 포함하는 “개인 정보 보호”를 의미하는 경우 잘못된 트리를 짖는 것입니다. Java 애플리케이션에서 민감한 데이터를 보호하는 방법은 민감한 데이터를 처리하는 보안 샌드 박스에 신뢰할 수없는 코드를 허용하지 않는 것입니다. Java 액세스 수정자는 보안 메커니즘이 아닙니다.
<문자열 예>-이것이 큰 관심사라고 생각하는 유일한 사람입니까?
아마도 유일한 것은 아닙니다 :-). 그러나 IMO, 이것은 문제가 아닙니다. 신뢰할 수없는 코드는 샌드 박스에서 실행되어야한다는 사실은 인정됩니다. 이와 같은 일을하는 신뢰할 수있는 코드 / 신뢰할 수있는 프로그래머가 있으면 문제가 예기치 않게 변경 가능한 문자열보다 더 나쁩니다. (논리 폭탄, 은밀한 채널을 통한 데이터 유출을 생각하십시오. )
개발 또는 운영 팀에서 “나쁜 행위자”의 문제를 처리 (또는 완화)하는 방법이 있습니다. 그러나 비용이 많이 들고 제한적이며 대부분의 사용 사례에서 과도합니다.
답변
반사는 실제로 이러한 관점에서 안전 / 보안과 직교합니다.
반사를 어떻게 제한 할 수 있습니까?
Java에는 보안 관리자 ClassLoader
가 있으며 보안 모델의 기반이됩니다. 귀하의 경우에는 java.lang.reflect.ReflectPermission
.
그러나 이것은 반성의 문제를 완전히 해결하지 못합니다. 사용 가능한 반사 기능은 현재는 그렇지 않은 세분화 된 권한 부여 체계의 적용을 받아야합니다. 예를 들어 특정 프레임 워크가 리플렉션 (예 : Hibernate)을 사용하도록 허용하지만 나머지 코드는 사용하지 않습니다. 또는 디버깅 목적으로 프로그램이 읽기 전용 방식으로 만 반영하도록 허용합니다.
미래에 주류가 될 수있는 한 가지 접근 방식 은 클래스에서 반사 기능을 분리하기 위해 소위 미러 를 사용하는 것입니다 . 미러 : 메타 레벨 시설의 설계 원칙을 참조하십시오 . 그러나이 문제를 다루는 다양한 다른 연구 가 있습니다. 그러나 나는 정적 언어보다 동적 언어에서 문제가 더 심각하다는 데 동의합니다.
반사가 우리에게주는 초능력에 대해 걱정해야합니까? 예, 아니오.
예 , Java 플랫폼이 Classloader
보안 관리자 와 함께 보호되어야한다는 점에서 그렇습니다 . 반사를 망칠 수있는 능력은 위반으로 볼 수 있습니다.
아니 의미에서 대부분의 시스템 어쨌든 것을 완전히 확보하지. 많은 클래스가 자주 하위 클래스 화 될 수 있으며 잠재적으로 이미 시스템을 남용 할 수 있습니다. 물론 수업을 만들 final
거나 봉인 할 수 있습니다. 하여 다른 jar에서 하위 클래스를 만들 수 없습니다. 그러나 이에 따라 올바르게 보호되는 클래스는 거의 없습니다 (예 : String).
이것 좀 봐 좋은 설명 은 최종 수업에 대한 답변을 . Sami Koivu 의 블로그 참조보안 관련 자바 해킹에 대한 자세한 내용 .
Java의 보안 모델은 어떤면에서는 불충분하다고 볼 수 있습니다. 다음과 같은 일부 언어NewSpeak 모듈성에 대해 훨씬 더 급진적 인 접근 방식을 취합니다. 여기서 종속성 반전 (기본적으로 아무것도 없음)에 의해 명시 적으로 제공되는 항목에만 액세스 할 수 있습니다.
어쨌든 보안이 중요하다는 점에 유의하는 것도 중요합니다. 상대적 . 예를 들어 언어 수준에서 모듈 양식이 CPU를 100 % 사용하거나 OutOfMemoryException
. 그러한 우려는 다른 방법으로 해결해야합니다. 우리는 향후 Java가 리소스 사용 할당량으로 확장되는 것을 볼 수 있지만 내일은 아닙니다. 🙂
나는 주제에 대해 더 확장 할 수 있지만, 내 주장을 내린 것 같다.