QUERY_STRING 을 Location 으로 전환
책의 정보를 보는 example.com/book.php?novel 라는 URL 이 있다. 이제 이 URL 을 example.com/book/novel 로 들어와도 정상 동작하게 설정해 보자.
RewriteRule ^/book/(.*) /book.php?$1 [L,PT]
여러 개의 QUERY_STRING 을 Location 으로 전환
위 예제는 잘 동작하지만 다음과 같은 경우 제대로 동작하지 않는다.
example.com/book.php?category=novel&bookid=1234
이 문제는 ? 뒤의 모든 파라미터를 하나의 파라미터로 전달하므로 발생한다. 다음과 같이 하면 URL 을 파싱해서 두 개의 파라미터로 변환해서 book.php 에 전달한다.
RewriteRule ^/book/([^/]*)/([^/]*) /book.php?category=$1&bookid=$2 [PT]
([^/]*) 정규식 패턴은 / 를 제외한 모든 문자를 의미하므로 URL 을 표현하게 된다.
기존 html 을 JSP 로 전환
사이트를 개편해서 기존 html 대신 jsp 를 제공하고 있다. URL 은 같고 파일의 확장자만 다를 경우 예전 html 을 호출하는 클라이언트는 다음 규칙을 통해 jsp 로 전환 시킬 수 있다.
RewriteRule ^/?([a-z/]+).html$ $1.jsp[L,R=301]
요청 리소스가 없을 경우 404 페이지로 전환
클라이언트가 요청하는 리소스가 없을 경우 별도의 에러 페이지로 전환 시킬 수 있다. 쉘 스크립트에서 사용되는 test 구문중 파일이 존재하는지를 판단하는 -f 와 디렉터리인지 판단하는 -d 옵션을 RewriteCond 에 사용할 수 있다.
다음 예제는 클라이언트가 요청한 파일 및 디렉터리가 존재하지 않을 경우 별도의 404 페이지를 실행하고 rewrite 처리를 종료하는 예제이다.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? /404.php [L]
리소스의 외부 링크 차단
HTTP 프로토콜은 요청을 보낼 때 이 URI 를 어디에서 알았는지에 대한 정보를 전송한다. 다시 말하면 링크를 타고 왔을 때 이 요청을 링크한 페이지의 URL 에 대한 정보이다.
이 HTTP 헤더를 리퍼러(Referer)라고 하며 이 정보를 이용하면 내부 페이지에서 링크되지 않고 외부에서 링크하여 들어오는 경우를 차단할 수 있다.
이 기능은 보통 이미지 파일등의 외부 링크를 차단할 때 많이 사용된다. 다음은 리퍼러가 example.com, 또는 www.example.com 이 아닐 경우 차단하는 예제이다. 링크된 페이지가 URL 에 대해 http 를 썼을 수도 있고 안 썼을 수도 있으므로 http:// 부분은 ? 문자로 처리해야 한다.
RewriteCond %{HTTP_REFERER} !^(https?:\/\/)?(www.)?example\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .(gif|jpe?g|png)$ - [F]
RewriteCond %{HTTP_REFERER} !^$ 가 있으면 리퍼가 정보가 없는 경우는 403 을 발생시키지 않는다.
이는 리퍼러 정보를 제대로 보내지 않는 브라우저나 또는 사용자가 페이지 북마크를 한 경우 처리하기 위함이나 이런 경우에도 다 차단하려면 이 항목을 주석 처리하면 된다.
ServerAlias 로 연결시 대표 이름으로 전환
가상 호스트 설정에 ServerName 은 example.com 이고 ServerAlias 는 www.example.com, web.example.com, home.example.com 이 있다고 하자. ServerAlias 로 연결할 경우 example.com 으로 전환하고 싶다.
다음 설정은 클라이언트가 Host: 헤더에 보낸 호스트 이름이 example.com 이 아닐 경우 example.com 으로 전환하는 예제이다. 클라이언트가 호스트 이름을 대문자로 쓸 수도 있으므로 NC 플래그를 붙이는게 좋다.
RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
RewriteRule (.*) http://example.com$1 [R,L]
HTTP 로 연결이 들어올 경우 HTTPS 로 전환
secure_page 디렉터리 밑에는 보안이 필요한 페이지들이 있다. 이 디렉터리 아래에 있는 모든 리소스들은 사용자가 실수로 http 로 들어와도 자동으로 https 로 전환하고 싶다.
다음 규칙으로 요구 사항을 충족할 수 있다.
RewriteCond %{REQUEST_URI} ^/secure_page/
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R,L]
모든 페이지를 HTTPS 로 전환
아주 중요한 서비스를 개발했고 모든 페이지에 HTTPS 를 적용하겠다고 가정해 보자. 고객은 보통 https 라는걸 잘 모르므로 이런 경우에도 http 포트를 열고 모든 http 는 https 로 전환하는게 좋다.
다음 규칙을 사용하면 모든 http 요청을 https 로 전환할 수 있다.
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R,L]
htaccess 와 RewriteRule, RewriteCond 정규표현식 규칙
RewriteRule Pattern Substitution
2. RewriteCond의 CondPattern을 지나 RewriteRule의 Substitution으로 처리되어 조건에 만족하게 된다.
* 요약1
[A] => 역시 하나의 문자가 올수 있다는 뜻.
[^A] => A문자는 올수 없다는 뜻.
? => 0개 또는 1개의 텍스트.
* => 0개 또는 1개 이상의 텍스트.
+ => 1개 이상의 텍스트. 0은 될수 없다.
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
RewriteRule ^([^.]+)\.test\.co\.kr(.*) /home/$1/htdocs$2
RewriteRule ^sub/(.*)/$ ./page/sub.php?page=$1
RewriteRule ^sub/(.*)/(.*)/$ ./page/sub.php?page=$1&nn=$2
RewriteRule ^sub/(.*)/(.*)/(.*)/$ ./page/sub.php?page=$1&nn=$2&sn=$3
RewriteRule ^sub/(.*)/(.*)/(.*)/(.*)/$ ./page/sub.php?page=$1&nn=$2&sn=$3&no=$4
이렇게 작성하면 http://localhost/sub/login/1/ 여기에 안들어가지고, 안됬던것들이
RewriteRule ^sub/([^/\.]+)/$ ./page/sub.php?page=$1
RewriteRule ^sub/([^/\.]+)/([^/\.]+)/$ ./page/sub.php?page=$1&nn=$2
RewriteRule ^sub/([^/\.]+)/([^/\.]+)/([0-9a-zA-Z-]+)/$ ./page/sub.php?page=$1&nn=$2&sn=$3
* 요약2
(.*) :한 글자 이상의 문자열(*이므로 한 글자도 없을 수도 있음, +라면 무조건 한 글자는 있어야 함)
([^/\.]+) : /와 .이 포함되지 않은 한 글자 이상의 문자열
([0-9a-zA-Z-]+) : 0부터 9, a부터 z, A부터 Z, -로 이루어져 있는 한 글자 이상의 문자열
([0-9a-zA-Z-]*) : 0부터 9, a부터 z, A부터 Z, -로 이루어져 있는 한 글자 이상의 문자열이지만 한 글자도 없을 수도 있음.
([0-9a-zA-Z-]{1}) : 0부터 9, a부터 z, A부터 Z, -로 이루어져 있는 한 글자
([0-9a-zA-Z-]{2,}) : 0부터 9, a부터 z, A부터 Z, -로 이루어져 있는 두 글자 이상의 문자열
([0-9a-zA-Z-]{2,4}) : 0부터 9, a부터 z, A부터 Z, -로 이루어져 있는 두 글자에서 4글자 이하의 문자열
[해결답변] (.*)로 했을 때 되지 않는 이유: (.*)은 /도 모두 포함하므로 URL의 끝까지 $1로 인식함. 다시 말하면 뭘 입력하든 첫 번째 'RewriteRule ^sub/(.*)/$ ./page/sub.php?page=$1'에서 모두 True가 되어버림. ([^/\.]+)로 하면 되는 이유: 입력값은 /를 포함하지 않아야 하므로 입력값에 따라 첫 번째 RewriteRule이 False가 되고 다른 RewriteRule을 체크할 수 있음. |
.: 다수의 한문자
?: 0개 이상의 한문자
*: 0개 이상의 문자 또는 문자열
+: 1개 이상의 문자 또는 문자열
(chars): (, ) 안의 문자또는 문자열을 그룹으로 묶습니다. 이 문자그룹은 Substitution(return URL)에서 $N 의 변수로 활용할수 있습니니다.
^: 문자열의 첫문(열)을 지정합니다.
$: 문자열의 끝 문자(열)을 지정합니다.
\(역슬래쉬): 정규표현식에서 특별한 의미로 사용되는 문자의 특수기능을 제거합니다.(예:(, ), [, ], . 등)
{n}: 정확히 n번 반복
{n,}: n번 이상 반복
{n,m}: n 이상 m 이하 반복
[chars]: 문자들의 범위 또는 표현할 수 있는 문자
ex) [a-z]: a 부터 z 까지의 소문자, [tT] : 소문자 t 또는 대문자 T
*정규표현식 단축표현
[:alpha:] : 알파벳. [a-zA-Z] 와 같은 표현
[:alnum:] : 알파벳과 숫자. [a-zA-Z0-9] 와 같은 표현
[:digit:] : 숫자 [0-9] 와 같은 표현
[:upper:] : 대문자. [A-Z] 와 같은 표현
-d: 디렉토리를 의미합니다. TestString이 이렉토리를 가리키거나 포함하고 있을 때 처리됩니다.
-f: 파일을 의미합니다. TestString이 파일을 가리키더나 포함하고 있을 때 처리됩니다.
-l: 심볼릭링크를 의미합니다. TestString이 심볼릭링크를 가리키거나 포함하고 있을 때 처리됩니다.
마지막으로 느낌표(!)는 부정을 뜻합니다.
*좋은예제2
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://test.domain.co.kr/$1
위 예제는 Request 내용이 디렉토리나 파일을 가리키고 있지 않을 경우 저쪽 사이트로 접속하게 만들라는 의미입니다. $1로 하위주소는 유지하고 있다.
* Flag
라인마다 Flag라 불리는 기능을 사용할 수 있다.
F: 403 Forbidden 에러 페이지를 출력합니다. 접근 권한이 없다는 의미.
L: Last(마지막)를 의미. Rewrite 끝.
N: 새로운 Rule이 시작된다는 의미.
QSA: Cond의 내용을 지난 결과 이어서 덧붙임.
NE: Out 될 값에 특수문자가 HexCode로 되어 포함되어 있는 경우
R: Redirection. 무조건 넘김. 뒤 주소로 넘긴다.
NC: 대소문자를 구별하지 않는다.
OR: 프로그래밍의 or.
위의 Flag들을 사용하여 아래와 같은 예제가 탄생했습니다!
RewriteCond %{REMOTE_HOST} ^domain.* [OR]
RewriteCond %{REMOTE_HOST} ^DOMAIN.* [OR]
RewriteCond %{REMOTE_HOST} ^DOMAIN2.* [NC]
RewriteRule ^(.*)$ http://www.domain.co.kr/$1 [R,L]
domain, domain2, DOMAIN, DOMAIN2로부터 접속한 경우 Redirect합니다. http://www.domain.co.kr로 접속하게 된다.
'Apache' 카테고리의 다른 글
아파치 서버 끊김없이 재시작 (graceful) - 무중단 재시작 (0) | 2017.11.23 |
---|---|
아파치 로그 포맷과 CustomLog 지시자, 로그변수 (0) | 2017.09.27 |
mod_security2 설치 (0) | 2017.09.22 |
apache 버전 감추기 (0) | 2017.09.10 |
아파치 (98)Address already in use: make_sock: could not bind to address 0.0.0.0:80 에러 발생시 해결방법 (0) | 2017.09.10 |
댓글