보안 점검에서 IIS 에 대해 지적되는 항목은 대개 둘이다. 하나는 서버 정보를 흘리는 응답 헤더와 없는 보안 헤더, 다른 하나는 낡은 TLS 버전과 암호 모음이다. 앞의 것은 IIS 관리자나 web.config 에서, 뒤의 것은 Windows 의 Schannel 레지스트리에서 다룬다. IIS 자체에는 암호 모음을 고르는 화면이 없다는 점이 혼동의 원인이다.
IIS 관리자에서 사이트를 고른 뒤 HTTP 응답 헤더(HTTP Response Headers) 기능에서 추가할 수 있고, 같은 내용을 web.config 로도 적을 수 있다. 설정을 형상 관리하려면 web.config 쪽이 낫다.
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
<add name="X-Frame-Options" value="SAMEORIGIN" />
<add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
<add name="Content-Security-Policy" value="default-src 'self'" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
각 헤더의 뜻은 다음과 같다.
| 헤더 | 역할 |
|---|---|
X-Content-Type-Options: nosniff |
브라우저가 Content-Type 을 무시하고 내용을 추측하는 것을 막는다 |
X-Frame-Options |
다른 사이트의 프레임에 끼워 넣는 클릭재킹을 막는다 |
Referrer-Policy |
다른 사이트로 나갈 때 넘기는 경로 정보를 줄인다 |
Strict-Transport-Security |
이후 접속을 HTTPS 로 강제한다 |
Content-Security-Policy |
브라우저가 불러올 수 있는 출처를 제한한다 |
Strict-Transport-Security 는 HTTPS 응답에만 붙여야 한다. HTTP 로도 서비스하는 동안 붙이면 되돌리기 어렵다. Content-Security-Policy 는 값을 잘못 주면 화면이 깨지므로 Content-Security-Policy-Report-Only 로 먼저 관찰한 뒤 적용한다.
X-XSS-Protection 은 예전 점검 목록에 자주 남아 있지만 현재 주요 브라우저가 해당 기능을 제거했다. 새로 넣을 이유가 없고, 값에 따라 오히려 취약점이 되는 사례가 알려져 있다. 대신 Content-Security-Policy 를 쓴다.
기본 상태의 IIS 와 ASP.NET 은 제품과 버전을 응답에 적어 보낸다. 제거 방법이 헤더마다 다르다.
| 헤더 | 제거 방법 |
|---|---|
X-Powered-By |
web.config 의 customHeaders 에서 <remove name="X-Powered-By" /> |
X-AspNet-Version |
<httpRuntime enableVersionHeader="false" /> |
X-AspNetMvc-Version |
애플리케이션 시작 코드에서 MvcHandler.DisableMvcResponseHeader = true |
Server |
IIS 10 이상은 requestFiltering 의 removeServerHeader="true" |
<configuration>
<system.web>
<httpRuntime enableVersionHeader="false" />
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering removeServerHeader="true" />
</security>
</system.webServer>
</configuration>
IIS 10 미만에서는 Server 헤더를 설정으로 지울 수 없어 URL Rewrite 모듈의 아웃바운드 규칙이나 HTTP 모듈을 써야 한다.
IIS 는 Windows 의 Schannel 을 그대로 쓴다. 따라서 프로토콜과 암호 모음은 레지스트리나 그룹 정책에서 바꾼다.
현재 지원 목록은 PowerShell 로 확인한다.
Get-TlsCipherSuite | Select-Object -Property Name
Get-TlsCipherSuite -Tls12 | Select-Object -Property Name
암호 모음을 개별로 끄고 켜는 명령도 있다.
Disable-TlsCipherSuite -Name TLS_RSA_WITH_3DES_EDE_CBC_SHA
Enable-TlsCipherSuite -Name TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
프로토콜 자체를 끄는 것은 레지스트리다. 경로는 다음과 같고 Server 와 Client 하위 키에 Enabled 와 DisabledByDefault 를 둔다.
HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\
$base = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server'
New-Item -Path $base -Force | Out-Null
New-ItemProperty -Path $base -Name Enabled -Value 0 -PropertyType DWord -Force
New-ItemProperty -Path $base -Name DisabledByDefault -Value 1 -PropertyType DWord -Force
Schannel 설정은 재부팅해야 완전히 반영된다. 서비스 재시작만으로는 이미 열려 있는 구성 요소에 적용되지 않는다.
Invoke-WebRequest -Uri https://example.com -UseBasicParsing | Select-Object -ExpandProperty Headers
외부에서는 curl -sI https://example.com 으로 헤더를 보고, TLS 협상 결과는 openssl s_client -connect example.com:443 -tls1_2 로 확인한다.
reg export "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL" C:\backup\schannel.reg