fix: ComResourceUtils의 XML 외부 엔티티(XXE) 취약점 수정 - #149
Conversation
web.xml 을 파싱하는 checkOldWebXml·modifyWebXml 의 DocumentBuilderFactory 에 같은 파일의 makeDocument 와 동일한 외부 엔티티 차단 설정을 적용한다.
dev 모듈과 동일한 미러 파일에 같은 설정을 적용한다.
|
전자정부 표준프레임워크에 기여해 주셔서 감사합니다. |
…로 통합 core 의 XmlUtil.applyXxeProtection 이 private 이라 commngt 와 mdev.commngt 의 ComResourceUtils 는 같은 외부 DTD·외부 엔티티 차단 설정 4줄을 파일마다 9곳에 인라인으로 복사하고 있었고, #149 도 같은 블록을 두 곳에 더 추가했다. 설정을 바꿀 때 18곳을 각각 고쳐야 하고 한 곳만 빠져도 방어 수준이 파일마다 달라진다. XmlUtil 에 보안 설정이 적용된 비검증 DocumentBuilderFactory 를 돌려주는 public 정적 메서드 newSecureDocumentBuilderFactory 를 두고, 두 ComResourceUtils 의 인라인 블록을 모두 이 호출로 바꾼다. validating, namespaceAware, load-dtd-grammar 처럼 파싱 의미를 정하는 옵션은 각 사이트에 그대로 남긴다. 헬퍼는 setFeature 의 ParserConfigurationException 을 개별로 삼키므로, 파서가 Apache 전용 feature 를 인식하지 못하는 환경에서 예외가 catch (Exception) 으로 빠져 파싱 전체가 건너뛰어지던 경로(mdev 는 checkOldWebXml 이 false 를 돌려 web.xml 이 병합 대신 템플릿으로 교체됨)가 사라진다. 또한 applyXxeProtection 을 재사용하므로 FEATURE_SECURE_PROCESSING 이 함께 켜지는데, JDK 내장 파서는 이미 기본값이 true 라 동작 차이는 없다. Refs: #149
|
이번에 추가한 그래서 #138 의 한 가지 참고로, dev 번들의 앞으로 사용자 프로젝트의 XML 을 |
문제
ComResourceUtils의checkOldWebXml()(183행 부근)과modifyWebXml()(248행 부근)은 사용자 프로젝트의web.xml을 아무 설정 없는DocumentBuilderFactory로 파싱합니다. 오염된web.xml이 있으면 XXE(CWE-611) 로 로컬 파일 읽기·SSRF 가 가능합니다.같은 파일의
makeDocument()는 이미 동일한 차단 설정을 가지고 있어, 이 두 메서드만 분방어 상태입니다. #138 리뷰에서 @swanpark8538 님이 알려주신 항목이며, 요청하신 대로 개별 PR 로 분리했습니다.변경
dev/mdev두 미러 파일의 해당 2개소(총 4개소)에 외부 엔티티·외부 DTD 차단 설정을 추가했습니다. 같은 파일makeDocument()가 이미 쓰는 설정과 동일한 목록이며, 파싱 의미를 바꾸는setValidating·setNamespaceAware는 건드리지 않았습니다.검증 (실측)
서블릿 DTD 를 외부 참조하는 전형적인 web.xml 2.3 문서로 변경 전/후를 비교했습니다.
checkServletMapping()이 사용하는 노드 구조는 동일하며, 외부 DTD 를 내려받지 않아 오프라인 환경에서의 지연도 사라집니다.<!ENTITY xxe SYSTEM "file:///...">): 변경 전에는 파일 내용이 그대로 치환되었고, 변경 후에는 치환되지 않습니다.<!ENTITY ver "4.3.0">)는 변경 전후 모두 Text 노드로 동일하게 치환됩니다 — XmlUtil의 XML 외부 엔티티(XXE) 취약점 수정 #138 리뷰에서 지적해 주신setExpandEntityReferences(false)류의 부작용은 없습니다.관련: #138