DAST 인증
인증된 스캔은 인증된 사용자가 할 수 있는 모든 기능을 수행할 수 있으며, 여기에는 데이터 수정 또는 삭제, 양식 제출, 링크 따르기 등이 포함됩니다.
인증된 스캔은 비프로덕션 시스템 또는 서버에서만 실행하세요.
인증은 DAST 스캔 전에 사용자를 로그인시켜 분석기가 취약점을 찾을 때 애플리케이션의 가능한 많은 부분을 테스트할 수 있도록 합니다.
DAST는 브라우저를 사용하여 사용자를 인증하여 로그인 양식에 제출하는 데 필요한 JavaScript와 스타일이 포함되도록 합니다.
DAST는 사용자 이름 및 비밀번호 필드를 찾아서 해당 값으로 채웁니다.
로그인 양식이 제출되고 응답이 반환되면 일련의 검사를 통해 인증이 성공했는지 확인합니다.
DAST는 크롤링할 대상 애플리케이션에서 재사용할 자격 증명을 저장합니다.
DAST가 인증에 실패하면 스캔이 중단되고 CI 작업이 실패합니다.
인증은 단일 단계 로그인 양식, 다단계 로그인 양식, 싱글 사인온 및 구성된 대상 URL 외부의 URL에 대한 인증을 지원합니다.
시작하기
DAST 인증된 스캔을 실행하려면:
- 인증을 위한 필수 조건을 읽으세요.
- 인증된 사용자의 랜딩 페이지로 대상 웹사이트를 업데이트하세요.
- 로그인 양식이 사용자 이름, 비밀번호 및 제출 버튼이 단일 페이지에 있는 경우, CI/CD 변수를 사용하여 단일 단계 로그인 양식 인증을 구성하세요.
- 로그인 양식이 서로 다른 페이지에 사용자 이름 및 비밀번호 필드가 있는 경우, CI/CD 변수를 사용하여 다단계 로그인 양식 인증을 구성하세요.
- 스캔 중에 사용자가 로그아웃되지 않았는지 확인하세요.
필수 조건
- 스캔 중에 인증하려는 사용자의 사용자 이름과 비밀번호가 있습니다.
- DAST가 애플리케이션에 인증할 수 있도록 알려진 제한 사항을 확인했습니다.
- 양식 인증 또는 HTTP 인증을 사용하는지 여부에 따라 필수 조건을 충족했습니다.
- 인증이 성공했는지 여부를 검증할 수 있는 방법에 대해 고민했습니다.
양식 인증
- DAST 프록시 기반 분석기 또는 DAST 브라우저 기반 분석기를 사용하고 있습니다.
- 애플리케이션의 로그인 양식 URL을 알고 있습니다. 또는 인증 URL에서 로그인 양식으로 가는 방법을 알고 있습니다 (자세한 내용은 로그인 양식으로 가기 위한 클릭 참조).
- DAST가 각 값을 입력하는 데 사용하는 사용자 이름과 비밀번호 HTML 필드의 선택자를 알고 있습니다.
- 선택할 때 로그인 양식을 제출하는 요소의 선택자를 알고 있습니다.
HTTP 인증
- DAST 브라우저 기반 분석기를 사용해야 합니다.
사용 가능한 CI/CD 변수
다음 CI/CD 변수를 사용하여 애플리케이션의 DAST 스캐닝에 필요한 인증 작업을 구성합니다.
CI/CD 변수 | 유형 | 설명 |
---|---|---|
DAST_AUTH_COOKIE_NAMES |
문자열 | 인증에 사용되는 쿠키 이름의 쉼표로 구분된 목록을 설정합니다. |
DAST_AUTH_REPORT |
불리언 | 인증 과정에서 수행된 단계를 자세히 설명하는 보고서를 생성하려면 true 로 설정합니다. 또한 생성된 보고서에 접근할 수 있도록 gl-dast-debug-auth-report.html 을 CI 작업 아티팩트로 정의해야 합니다. 이 보고서의 내용은 인증 실패를 디버깅하는 데 도움이 됩니다. |
DAST_AUTH_TYPE 1
|
문자열 | 사용할 인증 유형입니다. 예: basic-digest . |
DAST_AUTH_URL |
URL | 대상 웹사이트의 로그인 폼이 포함된 페이지의 URL입니다. DAST_USERNAME 과 DAST_PASSWORD 는 인증된 스캔을 생성하기 위해 로그인 폼과 함께 제출됩니다. 예: https://login.example.com . |
DAST_AUTH_SUCCESS_IF_NO_LOGIN_FORM |
불리언 | 로그인 폼이 제출된 후 로그인 폼이 없는지를 확인하여 인증 성공 여부를 검증합니다. 이 성공 검사는 기본적으로 활성화되어 있습니다. |
DAST_AUTH_SUCCESS_IF_ELEMENT_FOUND |
선택자 | 로그인 폼이 제출된 후 인증 성공 여부를 판단하는 데 사용되는 요소를 설명하는 선택자입니다. 예: css:.user-photo . |
DAST_AUTH_SUCCESS_IF_AT_URL |
URL | 로그인 폼이 제출된 후 인증 성공 여부를 판단하기 위해 브라우저의 URL과 비교되는 URL입니다. 예: "https://example.com/loggedin_page" . |
DAST_AUTH_BEFORE_LOGIN_ACTIONS |
선택자 |
DAST_USERNAME 과 DAST_PASSWORD 를 로그인 폼에 입력하기 전에 클릭할 요소를 나타내는 선택자의 쉼표로 구분된 목록입니다. 예: "css:.navigation-menu,css:.login-menu-item" . |
DAST_SCOPE_EXCLUDE_URLS |
URL | 인증된 스캔 중 건너뛸 URL입니다; 쉼표로 구분됩니다. 여러 URL을 일치시키기 위해 정규 표현식 구문을 사용할 수 있습니다. 예를 들어, .* 는 임의의 문자 시퀀스와 일치합니다. |
DAST_AUTH_FIRST_SUBMIT_FIELD |
선택자 | 다단계 로그인 과정에서 사용자名 폼을 제출하기 위해 클릭되는 요소를 설명하는 선택자입니다. 예: css:button[type='user-submit'] . |
DAST_AUTH_PASSWORD |
문자열 | 웹사이트에 인증하기 위한 비밀번호입니다. 예: P@55w0rd!
|
DAST_AUTH_PASSWORD_FIELD |
선택자 | 로그인 폼에서 비밀번호를 입력하는 데 사용되는 요소를 설명하는 선택자입니다. 예: id:password
|
DAST_AUTH_SUBMIT_FIELD |
선택자 | 단일 페이지 로그인 폼의 로그인 폼 또는 다단계 로그인 폼의 비밀번호 폼을 제출하기 위해 클릭되는 요소를 설명하는 선택자입니다. 예: css:button[type='submit'] . |
DAST_AUTH_USERNAME |
문자열 | 웹사이트에 인증하기 위한 사용자명입니다. 예: admin
|
DAST_AUTH_USERNAME_FIELD |
선택자 | 로그인 폼에서 사용자명을 입력하는 데 사용되는 요소를 설명하는 선택자입니다. 예: name:username
|
DAST_AUTH_DISABLE_CLEAR_FIELDS |
불리언 | 수동 로그인을 시도하기 전에 사용자명 및 비밀번호 필드를 지우지 않도록 설정합니다. 기본값은 false 입니다. |
DAST_AUTH_AFTER_LOGIN_ACTIONS |
문자열 | 로그인 후 로그인 검증 전에 실행할 작업의 쉼표로 구분된 목록입니다. 현재 “click” 작업을 지원합니다. 예: click(on=id:change_to_bar_graph),click(on=css:input[name=username])
|
대상 웹사이트 업데이트
대상 웹사이트는 DAST_WEBSITE
CI/CD 변수를 사용하여 정의되며, DAST가 애플리케이션을 크롤링하기 시작하는 URL입니다.
인증된 스캔에서 최상의 크롤 결과를 얻으려면 대상 웹사이트는 사용자가 인증된 후에만 접근 가능한 URL이어야 합니다.
종종, 이는 사용자가 로그인을 한 후 도착하는 페이지의 URL입니다.
예를 들면:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com/dashboard/welcome"
DAST_AUTH_URL: "https://example.com/login"
HTTP 인증을 위한 설정
HTTP 인증 스킴을 사용하려면, DAST_AUTH_TYPE
값을 basic-digest
로 설정할 수 있습니다.
Negotiate나 NTLM과 같은 다른 스킴도 작동할 수 있지만, 현재 자동 테스트 커버리지가 부족하여 공식적으로 지원되지 않습니다.
설정에는 DAST 작업을 위해 CI/CD 변수 DAST_AUTH_TYPE
, DAST_AUTH_URL
, DAST_USERNAME
, DAST_PASSWORD
가 정의되어야 합니다. 고유한 로그인 URL이 없는 경우 DAST_AUTH_URL
을 DAST_WEBSITE
와 동일한 URL로 설정하세요.
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_TYPE: "basic-digest"
DAST_AUTH_URL: "https://example.com"
YAML 작업 정의 파일에 DAST_USERNAME
과 DAST_PASSWORD
를 정의하지 마세요. 이는 보안 위험이 될 수 있습니다. 대신 GitLab UI를 사용하여 이들을 마스킹된 CI/CD 변수로 생성하세요.
자세한 내용은 사용자 정의 CI/CD 변수를 참조하세요.
프록시 기반 분석기는 인증 메커니즘으로서 기본 인증을 지원하지 않습니다. 해결 방법으로는 DAST_REQUEST_HEADERS
를 마스킹된 CI/CD 변수로 설정하고 적절한 Authorization
헤더를 포함하는 값을 제공하는 것입니다. 예를 들면, Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK
와 같습니다.
단일 단계 로그인 양식 설정
단일 단계 로그인 양식은 모든 로그인 양식 요소가 단일 페이지에 있습니다.
설정에는 DAST 작업을 위해 CI/CD 변수 DAST_AUTH_URL
, DAST_USERNAME
, DAST_USERNAME_FIELD
, DAST_PASSWORD
, DAST_PASSWORD_FIELD
, DAST_SUBMIT_FIELD
가 정의되어야 합니다.
작업 정의 YAML에서 URL과 필드 선택자를 설정해야 합니다. 예를 들어:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_URL: "https://example.com/login"
DAST_USERNAME_FIELD: "css:[name=username]"
DAST_PASSWORD_FIELD: "css:[name=password]"
DAST_SUBMIT_FIELD: "css:button[type=submit]"
YAML 작업 정의 파일에 DAST_USERNAME
과 DAST_PASSWORD
를 정의하지 마세요. 이는 보안 위험이 될 수 있습니다. 대신 GitLab UI를 사용하여 이들을 마스킹된 CI/CD 변수로 생성하세요.
자세한 내용은 사용자 정의 CI/CD 변수를 참조하세요.
다단계 로그인 양식 구성
다단계 로그인 양식은 두 개의 페이지로 구성됩니다. 첫 번째 페이지에는 사용자 이름과 다음 제출 버튼이 있는 양식이 있습니다.
사용자 이름이 유효한 경우 다음 페이지에서 비밀번호와 양식 제출 버튼이 있는 두 번째 양식이 표시됩니다.
구성하려면 DAST 작업에 대한 CI/CD 변수를 정의해야 합니다:
DAST_AUTH_URL
DAST_USERNAME
DAST_USERNAME_FIELD
DAST_FIRST_SUBMIT_FIELD
DAST_PASSWORD
DAST_PASSWORD_FIELD
-
DAST_SUBMIT_FIELD
.
작업 정의 YAML에서 URL 및 필드 선택기를 설정해야 합니다. 예를 들면:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_URL: "https://example.com/login"
DAST_USERNAME_FIELD: "css:[name=username]"
DAST_FIRST_SUBMIT_FIELD: "css:button[name=next]"
DAST_PASSWORD_FIELD: "css:[name=password]"
DAST_SUBMIT_FIELD: "css:button[type=submit]"
YAML 작업 정의 파일에서 DAST_USERNAME
및 DAST_PASSWORD
를 정의하지 마십시오. 이는 보안 위험을 초래할 수 있습니다. 대신 GitLab UI를 사용하여 마스크된 CI/CD 변수를 생성합니다.
자세한 내용은 사용자 지정 CI/CD 변수를 참조하세요.
싱글 사인 온(SSO) 구성
사용자가 애플리케이션에 로그인할 수 있는 경우, 대부분의 경우 DAST도 로그인할 수 있습니다.
애플리케이션이 싱글 사인온을 사용하는 경우에도 마찬가지입니다. SSO 솔루션을 사용하는 애플리케이션은 DAST 인증을 단계별 또는 다단계 로그인 형식 구성 가이드를 사용하여 구성해야 합니다.
DAST는 사용자가 외부 아이덴티티 공급자 사이트로 리디렉션되어 로그인하는 인증 프로세스를 지원합니다.
귀하의 SSO 인증 프로세스가 지원되는지 확인하려면 DAST 인증의 알려진 제한 사항을 확인하세요.
로그인 양식으로 이동 클릭
DAST_BROWSER_PATH_TO_LOGIN_FORM
을 정의하여 DAST가 로그인 양식에 액세스할 수 있도록 DAST_AUTH_URL
에서 클릭할 요소의 경로를 제공합니다.
이 방법은 로그인 양식이 팝업(모달) 창에서 표시되거나 로그인 양식에 고유한 URL이 없는 애플리케이션에 적합합니다.
예를 들면:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_URL: "https://example.com/login"
DAST_BROWSER_PATH_TO_LOGIN_FORM: "css:.navigation-menu,css:.login-menu-item"
사용자 이름 및 비밀번호 제출 후 추가 작업 수행
DAST_AFTER_LOGIN_ACTIONS
를 정의하여 사용자 이름 및 비밀번호 양식이 제출된 후 로그인 프로세스를 완료하는 데 필요한 일련의 작업을 제공합니다. 예를 들어, 제출 버튼을 누른 후 나타나는 모달 대화상자(예: “로그인 상태 유지?” 프롬프트)를 닫는 데 사용할 수 있습니다.
DAST는 로그인 후 작업이 실행된 후 인증이 성공했는지 확인하고 인증 토큰을 기록합니다.
예를 들면:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_URL: "https://example.com/login"
DAST_AFTER_LOGIN_ACTIONS: "click(on=id:modal-yes)"
로그아웃 URL 제외하기
DAST가 인증된 스캔을 실행하는 동안 로그아웃 URL을 크롤링하면 사용자가 로그아웃되어 나머지 스캔이 인증되지 않은 상태가 됩니다.
따라서 CI/CD
변수를 사용하여 로그아웃 URL을 제외하는 것이 좋습니다: DAST_EXCLUDE_URLS
. DAST는 제외된 URL에 접근하지 않으므로 사용자는 로그인 상태를 유지합니다.
제공된 URL은 절대 URL이거나 DAST_WEBSITE
의 기본 경로에 대한 URL 경로의 정규 표현식일 수 있습니다. 예를 들어:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com/welcome/home"
DAST_EXCLUDE_URLS: "https://example.com/logout,/user/.*/logout"
요소 선택자 찾기
선택자는 CI/CD 변수가 브라우저의 페이지에 표시된 요소의 위치를 지정하는 데 사용됩니다.
선택자는 type
:search string
형식을 가집니다. DAST는 유형에 따라 검색 문자열을 사용하여 선택자를 검색합니다.
선택자 유형 | 예제 | 설명 |
---|---|---|
css |
css:.password-field |
제공된 CSS 선택기를 가진 HTML 요소를 검색합니다. 성능상의 이유로 선택자는 가능한 한 구체적이어야 합니다. |
id |
id:element |
제공된 요소 ID를 가진 HTML 요소를 검색합니다. |
name |
name:element |
제공된 요소 이름을 가진 HTML 요소를 검색합니다. |
xpath |
xpath://input[@id="my-button"]/a |
제공된 XPath를 가진 HTML 요소를 검색합니다. XPath 검색은 다른 검색보다 성능이 떨어질 것으로 예상됩니다. |
제공되지 않음 | a.click-me |
기본적으로 CSS 선택기를 사용하여 검색합니다. {경고} 사용 중단됨 GitLab 15.8에서. 선택자 유형을 명시적으로 선언하여 교체되었습니다. |
Google Chrome으로 선택자 찾기
Chrome DevTools 요소 선택기 도구는 선택자를 찾는 효과적인 방법입니다.
- Chrome을 열고 선택자를 찾고자 하는 페이지로 이동합니다. 예를 들어, 귀하의 사이트의 로그인 페이지입니다.
- macOS에서는 клавиатуры 단축키
Command + Shift + c
를, Windows에서는Ctrl + Shift + c
를 사용하여 Chrome DevTools의Elements
탭을 엽니다. -
페이지에서 선택할 요소 선택
도구를 선택합니다. - 선택자의 구성을 알고 싶은 페이지의 필드를 선택합니다.
- 도구가 활성화되면 세부 정보를 보고자 하는 필드를 강조 표시합니다.
- 강조 표시한 후, 선택자로 사용할 수 있는 요소의 세부정보와 속성을 볼 수 있습니다.
이 예제에서 id="user_login"
이 좋은 후보로 보입니다. 이를 선택자로 사용할 수 있으며, DAST 사용자 이름 필드로 설정하면 됩니다: DAST_USERNAME_FIELD: "id:user_login"
입니다.
적절한 선택자 선택하기
신중한 선택자 선택은 애플리케이션 변경에 강한 스캔을 이끌어냅니다.
선호하는 순서에 따라 선택자로 선택해야 하는 것은 다음과 같습니다:
-
id
필드. 이러한 필드는 일반적으로 페이지에서 고유하며, 변경되는 경우가 드뭅니다. -
name
필드. 이러한 필드는 일반적으로 페이지에서 고유하며, 변경되는 경우가 드뭅니다. - 필드에 특정한
class
값, 예를 들어username
필드에 대한 선택자"css:.username"
와 같은 값. - 필드에 특정한 데이터 속성이 존재하는 경우, 예를 들어
data-username
필드에 값이 있을 때의 선택자"css:[data-username]"
. - 다수의
class
계층 값, 예를 들어username
클래스가 있는 여러 요소가 있지만login-form
클래스가 있는 요소 안에만 하나가 포함될 때의 선택자"css:.login-form .username"
.
특정 필드를 찾기 위해 선택자를 사용할 때 피해야 할 사항은 다음과 같습니다:
- 동적으로 생성된 모든
id
,name
,attribute
,class
또는value
. - 일반적인 클래스 이름, 예:
column-10
및dark-grey
. - XPath 검색, 이는 다른 선택자 검색보다 성능이 덜 좋습니다.
- 제한되지 않은 검색, 예를 들어
css:*
또는xpath://*
로 시작하는 것.
인증 성공 여부 확인하기
DAST가 로그인 양식을 제출한 후, 인증이 성공했는지 여부를 확인하는 프로세스가 진행됩니다. 인증이 실패하면 스캔이 오류로 중단됩니다.
로그인 양식을 제출한 후, 인증이 실패한 것으로 판단되는 경우는 다음과 같습니다:
- 로그인 제출 HTTP 응답에
400
또는500
시리즈 상태 코드가 포함되어 있는 경우. - 검증 확인이 실패하는 경우.
- 인증 프로세스 중에 충분히 무작위 값의 인증 토큰이 설정되지 않은 경우.
검증 확인
검증 확인은 인증이 완료된 후 브라우저의 상태에 대한 검사를 수행하여 인증 성공 여부를 추가로 판단합니다.
DAST는 검증 확인이 구성되지 않은 경우 로그인 양식이 없는지를 테스트합니다.
URL을 기반으로 검증하기
로그인 양식이 성공적으로 제출된 후 브라우저 탭에 표시되는 URL을 DAST_AUTH_VERIFICATION_URL
로 정의합니다.
DAST는 인증 후 브라우저의 URL과 검증 URL을 비교합니다. 두 URL이 다르면 인증이 실패한 것입니다.
예제:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_VERIFICATION_URL: "https://example.com/user/welcome"
요소의 존재 여부를 기반으로 검증하기
로그인 양식이 성공적으로 제출된 후 페이지에 표시되는 하나 이상의 요소를 찾는 선택자를 DAST_AUTH_VERIFICATION_SELECTOR
로 정의합니다. 요소가 발견되지 않으면 인증이 실패한 것입니다.
로그인 실패 시 표시되는 페이지에서 선택자를 검색하면 요소가 없음을 반환해야 합니다.
예제:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_VERIFICATION_SELECTOR: "css:.welcome-user"
로그인 양식의 부재에 기반하여 검증하기
로그인 양식이 성공적으로 제출된 후 페이지에서 로그인 양식을 검색해야 한다는 것을 나타내기 위해 DAST_AUTH_VERIFICATION_LOGIN_FORM
을 "true"
로 정의합니다. 로그인 후에도 로그인 양식이 여전히 존재하면 인증이 실패한 것입니다.
예제:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_VERIFICATION_LOGIN_FORM: "true"
인증 토큰
DAST는 인증 과정에서 설정된 인증 토큰을 기록합니다.
DAST가 새 브라우저를 열 때 인증 토큰이 로드되므로 사용자는 스캔하는 동안 로그인 상태를 유지할 수 있습니다.
토큰을 기록하기 위해 DAST는 인증 과정 전에 애플리케이션에 의해 설정된 쿠키, 로컬 스토리지 및 세션 스토리지 값을 스냅샷으로 찍습니다.
DAST는 인증 후에도 동일한 작업을 수행하고 인증 과정에서 생성된 항목을 결정하기 위해 차이를 사용합니다.
DAST는 적절히 “무작위” 값으로 설정된 쿠키, 로컬 스토리지 및 세션 스토리지 값을 인증 토큰으로 간주합니다.
예를 들어, sessionID=HVxzpS8GzMlPAc2e39uyIVzwACIuGe0H
는 인증 토큰으로 간주되는 반면, ab_testing_group=A1
은 그렇지 않습니다.
CI/CD 변수 DAST_AUTH_COOKIES
를 사용하여 인증 쿠키의 이름을 지정하고 DAST에서 사용되는 무작위성 체크를 우회할 수 있습니다.
이렇게 하면 인증 과정을 더욱 견고하게 만들 수 있을 뿐만 아니라 인증 토큰을 검사하는 체크에 대한 취약점 확인 정확도를 높일 수 있습니다.
예를 들어:
include:
- template: DAST.gitlab-ci.yml
dast:
variables:
DAST_WEBSITE: "https://example.com"
DAST_AUTH_COOKIES: "sessionID,refreshToken"
알려진 제한 사항
- DAST는 인증 흐름에 CAPTCHA가 포함된 경우 이를 우회할 수 없습니다. 스캔할 애플리케이션의 테스트 환경에서 이를 끄세요.
- DAST는 SMS, 생체 인식 또는 인증자 앱을 통해 일회성 비밀번호(OTP)와 같은 다단계 인증을 처리할 수 없습니다. 스캔할 애플리케이션의 테스트 환경에서 이를 끄세요.
- DAST는 로그인할 때 인증 토큰을 설정하지 않는 애플리케이션에 인증할 수 없습니다.
- DAST는 두 개 이상의 입력란을 채워야 하는 애플리케이션에 인증할 수 없습니다. 두 개의 입력란, 즉 사용자 이름과 비밀번호를 제공해야 합니다.
- DAST는 크롤링 단계에서 IndexedDB의 내용을 포함하지 않습니다. 애플리케이션이 인증된 상태를 유지하기 위해 IndexedDB에 의존하는 경우, DAST는 애플리케이션을 크롤링하기 위해 인증할 수 없습니다.
문제 해결
자세한 내용은 문제 해결을 참조하세요.