1. setuid wrapper CGI ¶
CGI실행파일을 setuid wrapper로 만들어주는 것이 낫지 않을까요? 지금은 그냥 python script파일을 setuid없이 작동시키고 있는데, 생성되는 데이터파일의 소유자가 nobody로 생성되고, 외부 공격으로 계정의 데이터를 모두 잃어버리는 불상사를 겪을 수도 있습니다. 간단히 C로 작성한 wrapper를 올립니다. 이 파일을 compile하여 chmod 6755 정도로 세팅한 후 이용하시기 바랍니다. --Aragorn
#include <stdio.h> #include <unistd.h> #include <errno.h> #define EXEC "/home6/Jimmy/WikiWiki/moin.py" /* 각자의 moin.cgi 파일 위치 */ int main(int argc, char *argv[]) { int r; r = execv(EXEC, argv); /* below is error handler. */ printf("Content-type: text/plain\n\n"); printf("Error occurred while executing program, [%s].\n", EXEC); printf("------------------------------------------------------------------------\n"); printf("exec returned %d and errno is [%s]\n", r, sys_errlist[errno]); printf("------------------------------------------------------------------------\n"); exit(0); }
Note: 서버 관리자라면 아예 apache 서버를 suexec 기능을 가지도록 설치하세요. Apache SuEXEC
보통은 관리자권한이 없어서 suexec를 설치하지 못하기도 하지만, 많은 사람들이 이미 suexec없이 CGI를 사용해 왔다면, 관리자도 쉽게 suexec를 적용하지 못합니다. suexec를 적용하게 되면, 많은 CGI들이 곧바로 에러를 내면서 작동을 멈추어 버리고, suexec 자체도 setuid CGI의 실행을 거부하는 기능을 갖고 있습니다. apache의 문제이긴 하나, suexec를 선택적으로 적용시킬 수 있는 기능을 제공하지 않는 것은 문제가 있어 보입니다. 물론 apache개발자들의 의도는 그렇게 예외적인 구멍을 만들 수 있으면 suexec의 존재 자체가 무의미하다는 것이겠지만.
생성되는 데이터파일의 소유자가 nobody로 생성되고, 외부 공격으로 계정의 데이터를 모두 잃어버리는 불상사를 겪을 수도 있습니다.
setuid없이 디렉토리를 setgid하여, 그 안에 생성되는 파일을 사용자가 지우거나 관리할 수 있게 하기도 합니다. 노스모크모인모인의 경우는 data디렉토리를 setgid로 설정하면 되겠지요.
2. data 디렉토리의 보안 ¶
data 디렉토리를 웹으로부터 분리시키는 것도 관리자들이 주의해야합니다. 자칫하면 패스워드가 누출될 수 있습니다.
안정버전을 그대로 설치하고나면 절대경로로 대충 ~/public_html/wiki/data 정도에 data 디렉토리가 위치해 있을텐데, 이 data 디렉토리를 ~/wikidata/myWiki 정도로 옮기고 moin_config.py 에서 data 의 경로를 절대 경로로 지정하면 data 디렉토리가 www 에 노출됨으로 인해 생기는 보안문제는 막을 수 있을 것입니다.
data의 디렉토리 퍼미션은 771로 하고 아파치를 위한 .htaccess파일을 다음과 같이 만들면 웹상에 노출되지 않습니다.
.htaccess 파일 내용 Order allow,deny Deny from all
3. 주소 리다이렉트 ¶
어떻게하면 http://wiki.justluv.net/FrontPage 식으로 쓸 수 있나요? 보통은 /moin.cgi/ 를 붙이잖아요. 저는 index.cgi로 이름을 바꿔서 http://choijw.net/?ICU 까지는 됩니다. 어서 비법을 전수해 주시지요 . --최종욱
저는 mod_rewrite를 사용합니다. 해당 디렉토리의 .htaccess 파일에 다음 내용을 추가합니다. 아마 더 좋은 방법이 있겠지요. -- DaNew
이렇게는 안 되나요? 바로 루트로 가게요.
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^([^\.\?/]+)/$ /moin/$1 [QSA] RewriteRule ^([^\.\?/]+)$ /moin/$1 [QSA] </IfModule>
... RewriteRule ^([^\.\?/]+)/$ /$1 [QSA] RewriteRule ^([^\.\?/]+)$ /$1 [QSA] ...
아샬은 이런 식으로 사용합니다.
http://blahblah.net/wiki/
로 접근하려면 wiki 디렉토리를 만들고 .htaccess파일을 다음과 같이 만듭니다.Action x-wiki-page /path_to/moin.cgi SetHandler x-wiki-page이 방법을 사용한다면 http://wiki.justluv.net/FrontPage이런 식은 곤란합니다. ( 아예 루트가 막혀버리는 꼴이 되니까요 ) http://no-smok.net/ns/moin.cgi이런 식으로 설치를 하신 후, http://no-smok.net/nsmk/ 이런 식으로 접근을 해야겠죠
httpd.conf를 편집할 수 있는 권한이 된다면,
ScriptAlias /mywiki /path_to/moin.cgi
4. 노스모크 미러 ¶
노스모크 가져가서 보존하거나, 인터넷에 연결되지 않았을 때에도 노스모크를 읽고 싶은 경우에 사용할 수 있는 방법
#!/bin/sh # ex:ts=2:et # # Full Wiki Downloader by PERKY # # requires: python, fetch, awk, sed WIKIURL="http://no-smok.net/nsmk/" TITLEINDEX="?action=titleindex" EDITACTION="?action=edit" DESTDIR="data" ERRLOG=".errlog" fetch -o - "$WIKIURL$TITLEINDEX" | \ python -c ' import urllib,sys print "\n".join([urllib.quote(x).replace("%", "_") for x in sys.stdin.read().split()])' \ > .TitleIndex mkdir -p $DESTDIR for page in `cat .TitleIndex`; do #page=`echo "$page" | sed -e 's,/,_2f,g' -e 's,_,_5f,g'` echo ">>> Retrieving page \"$page\" ..." fetch -q -o - "$WIKIURL$page$EDITACTION" 2>$ERRLOG \ | awk ' BEGIN { p = 0 } /^<\/textarea/ { p = 0 } /^<textarea/ { p = 1 } { if (p) { print; } }' \ | sed -e 's,^<textarea[^>]*>,,g' > "$DESTDIR/$page" done
PageName?action=raw
을 써서 간단히 구현한 것. 아래의 방법으로 하면 bash와 lynx와 같은 텍스트 웹브라우저만 있어도 되는 방법입니다. SLEEP값을 조절하여 노스모크에 무리를 주지 않고도 받을 수 있습니다. --고무신사용법:
다음과 같이 하면 my_directory가 만들어지고 그 밑으로 다운로드 됩니다. $ moinfetch.sh http://no-smok.net/nsmk/ my_directory
moinfetch.sh #!/bin/bash # requires: lynx FETCH='lynx -source' URL=$1 TARGET=$2 SLEEP=1 if [ ! -d $TARGET ]; then mkdir -p $2 fi PAGES=`$FETCH "$1?action=titleindex"` echo "*** Fetch all pages in $1" for page in $PAGES; do echo "**** $page" npage=`echo $page|sed 's@/@_2f/@g'` $FETCH "$1/$page?action=raw" > $TARGET/$npage 2>>fetch_log sleep $SLEEP done
#!/usr/bin/perl # 페이지 이름을 모인모인형식으로 바꾸기 위한 스크립트 # rename.pl # ls | perl rename.pl |sh while (<>) { chop($_); $save = $_; s/[^a-zA-Z0-9:\.\-\/]/sprintf("_%02x", ord($&))/ge; if ($save != $_) { print "mv -- $save $_\n"; # `mv -- $save $_`; } }
AutoMate 같은 자동화 소프트웨어(이 소프트웨어는 MicrosoftWindows 용)를 이용하여 raw 파일을 crawling하는 방법도 있습니다. --PuzzletChung
5. 백업 지우기 스크립트 ¶
sh moinclean.sh my_dir/data/backup
하면 백업된 내용만 보여주고, 지우려면sh moinclean.sh my_dir/data/backup | sh
라고 합니다. --고무신- 절대경로를 써주거나 위의 예처럼 해야 합니다. './ ../'가 경로에 들어있으면 안됩니다.
- 한번 생성된 페이지의 backup은 설령 그것이 필요 없을지라도 계속 남아있게 됩니다.
$BACKUP_COUNT
를 조절하여서 마지막 몇개까지 남길것인지 정합니다.#!/bin/bash # $Id: _eb_85_b8_ec_8a_a4_eb_aa_a8_ed_81_ac_eb_aa_a8_ec_9d_b8_eb_aa_a8_ec_9d_b8_2f_ed_8c_81,v 1.1 2007/05/13 15:48:53 no-smok Exp no-smok $ DATA_DIR=$1 # 마지막 두개를 남긴다. BACKUP_COUNT=2 # 3개월 전을 지운다. DATE=`date --date '3 month ago' +%s` if [ x$1 == x ]; then echo "usage: $0 <backup directory>" echo " ex) sh $0 data/backup |sh 2>log" exit fi PAGES=`find $1/ -type f | cut -d'.' -f 1 | sort | uniq` for X in $PAGES; do count=`ls $X.* | wc -l` count=`expr $count` echo " * $count : $X" >> /dev/stderr count=`expr $count - $BACKUP_COUNT` if [ $count -gt 0 ]; then BACKUPS=`ls $X.* | cut -d'.' -f 2 | sort | head -$count` i=0 for B in $BACKUPS; do i=`expr $i + 1` [ $B -gt $DATE ] && break echo " $i. $B" >> /dev/stderr echo "rm $X.$B" done fi done
DeleteThisPage 태그를 남길 때 마지막 모든 내용을 지우고 DeleteThisPage를 남기면, 마지막 파일 두개는 남겨야 지우기 전에 무슨 내용이 있었는지가 기록에 남게되겠군요.