이 글은 https://www.tokyobranch.net/archives/6693 과 https://www.tokyobranch.net/archives/7066 에 대한 반박글입니다. (네. 떡밥을 물고 말았습니다)
떡밥을 물며
트위터를 하다가 케케묵은 떡밥인 PHP 떡밥을 보았습니다. 보통 때 같았다면, 그냥 그저 그런 떡밥으로 넘겼겠지만 루아에 고통받고 있던 터라 빡치는 김에 떡밥을 물고 결국 이 글을 씁니다.
해당 글에서는 PHP 를 써야 하는 이유로
- PHP 는 언어 정책이 보수적이다
- 보안이나 성능 이슈는 PHP가 알아서 해 줄 것이다.
- PHP 를 세계적으로 많이 쓰는 이유가 뭐겠느냐
- PHP가 ORM과 같은 노가다를 대신 해준다
정도를 들고 있지만, 사실 이것들은 잘못되었습니다.
1. 언어 정책이 보수적이다
음 PHP 의 언어 정책에 정확한 이름을 붙이자면 그건 방임이지 보수적임이 아니겠죠
PHP는 많은 메소드들을 deprecation 시켰지만, 이를 제 때 처리하지 않았습니다. 대표적으로 mysql_* 함수들의 deprecation1 이 있는데, 이는 2012년도에 결정됬음에도, 이를 7.0 에 와서야 치웁니다2.
그리고 많은 수의 PHP개발자들은 Deprecation 경고에 신경을 전혀 쓰지 않았고, 그 결과는 Deprecated 된 함수의 지속적인 사용을 유발했습니다.
2. 보안 이슈를 PHP가 알아서 해 줄 것이다.
PHP는 보안 이슈에 있어서는 쥐약입니다. PHP언어 자체의 일관성이 상실된3 점이 프로그래머의 무관심과 시너지를 일으켜, 정말 골 때리는 문제를 양산하게 됩니다.
지천에 널려 있는 자질 미만의 프로그래머들이 ‘싼’ 코드들이 일으키는 SQLi 문제는 일단 넘어가더라도(SQL 에 $_COOKIE 를 concat 한다던가) 언어 자체에서 의도치 않은 함정들이 있습니다. 대표적 예로 PHP의 $_GET $_POST $_COOKIE 등이 있는데, 대부분의 경우, 이 변수들의 값은 문자열의 어레이입니다.
하지만 아래와 같은 쿼리 스트링이4 들어오면 어떻게 될까요?
http://example.com/vuln.php?query[()%20{%20example;};echo%20\%22Content-type:%20text/plain\%22;%20echo;%20echo;%20/bin/cat%20/etc/shadow%22]=test
이 쿼리 스트링을
print("\$_GET = "); $foo=array(); print_r($_GET); print('
'); print_r($_GET['query']);
에 넣어 보면 다음과 같은 결과를 출력합니다
$_GET = Array ( [query] => Array ( [() { example;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/shadow"] => test ) ) Array ( [() { example;};echo \"Content-type: text/plain\"; echo; echo; /bin/cat /etc/shadow"] => test )
대부분의 경우, $_GET 과 같은 변수로 문자열이 들어올 것으로 예상하고 코드를 작성하기에 이는 잠재적으로 문제를 일으킬 가능성을 증가시킵니다.
이 부분 이외에도, PHP가 암묵적으로 eval() 을 하는 것과 같은 효과를 내는 부분은 또 있습니다
PHP 에서 다음 코드를 실행시키면 어떻게 될까요
$foo = 'phpinfo'; $foo();
놀랍게도 phpinfo() 가 실행되게 됩니다. 이는 잘못 짜여진 코드에서 Function injection5 과 같은 공격을 허용하게 됩니다.
이러한 공격을 막기 위해서는, 입력을 점검하고 필터링하는 노력이 필요한데, 이는 다른 언어에서는 필요 없는 (입력이 string 인지 object 인지 함수인지 체크하는) 작업입니다.
C 같은 경우는, 문자열을 함수 포인터로 잡아 호출하려 할 경우, SIGSEGV 를 내며 죽을 것입니다.
Javascript 는 “foo is not a function” 이라는 오류를 내며 죽을 것입니다.
Java 는 아예 컴파일이 안 될 것입니다.
또한 대부분의 웹 프레임워크들은 PHP처럼 유저 인풋을 어레이로 취급해서 어레이를 만들어준다던가 하는 미친 짓을 하지 않습니다. 예로, NodeJS 의 대표적인 웹 프레임워크인 ExpressJS 의 경우, req.query[“blah[]”] 와 같은 식으로 유저 인풋을 멋대로 가공하지 않고 그대로 넘겨주게 됩니다. 2017-02-17 갱신: ExpressJS 의 경우, ?foo=1&foo=2 와 같은 경우에 foo = [1, 2] 와 같이 결과를 냅니다6. 이는 프로그램이 예상하지 않은 곳에서 크래시날 수 있게 하는 문제를 유발할 수 있습니다. 하지만 PHP 처럼 eval 에 준하는 오류를 일으키진 않으므로 상대적으로 안전합니다.
결국 PHP를 사용함에 있어, 다른 언어를 사용할 때와 비교해서 더 많은 보일러플레이트 코드가 발생하게 됩니다.
3. PHP를 많이 쓴다
PHP 는 인터넷 붐 초창기에 빠르게 퍼져나갔습니다. 결국 악화가 양화를 구축하게 된 대표적 사례라고 할 수 있을 법한 케이스죠.
언어가 많이 쓰인다고 해서 언어의 구림을 커버칠 순 없습니다.
3-1. WP, FB가 PHP를 쓴다.
네 MOSFET만을 가지고 손으로 CPU를 만들 수도7 있죠. 이쑤시개를 가지고도 건축을 할 수 있을 거고요. 헥사 에디터만 있어도 로버의 라디오를 리프로그램할 수 있겠죠8.
하지만 우리가 고수준 언어를 쓰는 이유는 효율성 때문입니다. 그리고 PHP는 많은 보일러플레이트 생성과, 템플릿과 코드의 혼합으로 이를 해칩니다.
실제로 Automattic 의 Jetpack 코드는 PHP프로젝트 치고는 깔끔한 편입니다. 하지만, 이를 수정하려고 하는 작업은, PHP의 템플릿과 코드의 혼합으로 인해 굉장히 까다롭게 됩니다.
또한 안전을 위한, 혹은 동작에 필수적인 수 많은 보일러플레이트들의 존재는 프로그래머가 실수할 가능성을 증가시킵니다. 이는 결국 효율성 저하로 이어지고요.
Facebook 은 PHP를 견디다 못해 직접 언어를 만든 케이스입니다. HHVM 을 만들면서 PHP와 연동이 가능한 Hacklang9 을 만들어서 사용하고 있죠. Facebook 을 두고 PHP를 사용하는 회사라고 부르기엔 이젠 무리가 있겠네요.
4. PHP는 ORM 같은 노가다를 대신 해 준다.
원 글이 ORM이라 부르는 것을 봅시다
그런데 이 과정에는 최소한 두가지의 노가다 작업이 필요합니다. 유저에게서 입력받은 데이터가 정상인지 체크하는 Server side validation과, DB의 데이터를 프로그램에서 사용할 수 있는 형식으로 변환해 주는(퉁쳐서 ORM이라고 부르기도 하는) 작업입니다. 이 이외에도 수많은 노가다가 존재합니다만(파일 업로드 처리라던가 pagination이라던가 나열하면 끝이 없습니다.) 이 두가지는 작업량도 많은데다 이미 존재하는 사양을 코드로 변환하는 단순한 과정이기에 재미도 없습니다. 이 중에서 Server side validation은 모든 입력을 대상으로 하지 않으면 보안에 구멍이 생기지만, 안해도 어차피 티가 잘 안나는 작업이라서 누구에게도 인기가 없습니다.
DB 의 데이터를 프로그램에서 사용할 수 있는 형식으로 번환해 주는 것은 데이터베이스 드라이버지, ORM 이 아닙니다. ORM은 보통 Getter 와 Setter 를 통해 SQL을 생성하고, 이를 쿼리하고, 이 결과를 프로그래머가 지정한 구조대로 맞추어 주는 것을 말합니다.
결국, 편하게 DB를 액세스하기 위해서는 ORM 라이브러리를 사용해야 하는 것은 변하지 않습니다.
또한, 위에서도 짚었지만, PHP는 보일러플레이트 필요로 인해 오히려 프로그래머의 노가다를 증가시키지, 감소시키진 않습니다. 유지보수성 낮은 PHP에게 정신력을 빼앗기는 꼴이죠.
마무리
다르다와 틀리다는 다릅니다. 하지만 PHP는 틀렸습니다.
물론 모던 PHP가 PHP5.x 시절의 과오를 고치려고 하는 것은 맞습니다. 하지만, 이제 다른 웹 개발 분야에서 뜨는 언어에 비해 PHP가 가지는 장점은 많이 흐려진 상태입니다. Deploy 에서도 버전별로 갈리고, 프로덕션 환경에서는 PHP5.x 와 PHP7 간의 호환성 문제 덕분에 닭장 웹호스팅 (Cafe24 의 PHP호스팅을 생각하시면 됩니다) 같은 상품 중에서 모던 PHP를 제공하는 부류는 소수입니다.
개인적인 생각으로는, 언어 자체에 결점을 많이 가지고 있는 PHP가 이제 디플로이마저 어려우면, PHP의 메리트는 이제 굉장히 낮다고 생각합니다. 차라리 Python 이나 Javascript (NodeJS) 나 다른 좋은(그리고 제정신인) 고수준 언어를 쓰시고 정 안되면 C(libcgi) 로 짜세요(비꼼) 그게 더 정신력 코스트를 아낄 수 있을 겁니다.
덧:
count() 가 7.2 들어서 제 정신을 차리려고 하는 건 좋은데 워드프레스 코드조차 해당 코드에서 터지는군요
PHP 좋아하시는 분들은 count() 에 Countable IF 를 달고 있지 않은 객체가 들어와도 오류가 나지 않고 0을 반환하고 심지어 미정의된 변수가 들어와도 0을 반환하는 이런 API 가 정녕 사람이 제 정신을 가지고 작성한 API 명세라고 생각하십니까?
- https://wiki.php.net/rfc/mysql_deprecation
- https://wiki.php.net/rfc/remove_deprecated_functionality_in_php7
- https://php-a-fractal-of-bad-design-kr.github.io/ 참조
- http://security.stackexchange.com/a/128594
- https://www.owasp.org/index.php?title=Function_Injection
- https://github.com/expressjs/express/issues/1824
- http://monster6502.com/
- 마션의 그 장면
- http://hacklang.org/
정말 우물안 개구리네요
시대가 어느때인데
예전같으면 저도 php 까재꼇겟지만
현실이 그렇지가 못하네요
기존 레거시 프로젝트를 이어가야 한다면 어쩔 수 없지만 신규 프로젝트를 PHP로 하는 건 충분히 미친 짓이라고 생각합니다.
더 좋은 대안이 많은데 안 쓰는 건 생산력만 떨어뜨릴 뿐이죠
너무ㅋㅋ웃기신분이네요
이시대에 다른언어를 까재끼는 분이잇을줄은. . 솔직히 이제까지 개발하면서 java가좋다 asp가좋다 파이썬이 좋다. . 이건아니다 . .하는분들중 개발잘하시는분들은 본적이 없네요ㅋㅋ
솔직히 이러고잇는 님이좀 웃기구요
Php가 이젠 왜까여야 하는지 전혀모르겟어요 정말modern php라는걸 접하고 나면 오히려 혁명적이라고 생각이들죠.
본인도 그렇게 느낀 1인이구요
그리고 이런 글을 적을시간에 정말 저논리를 납득시킬만한 사람이되세요.
님이 그런영향을 줄수잇는 자리에서 저런말을 한다면 누구나 고개를 끄덕이겟지만
현재 듣보의 상태로 저렇게 까재끼는 글만적는다면 나는 모자른놈이다 라고 직접 말하는거 아닌가쉽네요ㅎ 그럼 진짜 실력잇는 개발자가 되길바라며 답을 마칩니다
라라벨은 써보셨어요?
닉에 맞는 답변을 드리죠.
좋은 기반은 더 적은 노력을 통해 더 나은 결과를 도출해냅니다.
개판인 기반을 가지고 개판을 감출 핵을 올리는 것보다는 아예 더 나은 기반으로 가는 게 낫다는 말입니다.
물론 생산성이 좋은 도구는 언재든지
환영이에요.
그러나, 말씀하시는게 너무 과격해서
눈살이 찌푸려지는건 어쩔 수 없네요.
님이 php 뿐만아니라 다른언어로 얼마나 개발을 했는지는 모르겠지만.
분명히 님도 자주 애용하는 메인 언어가 있을거에요.
그런데 그것을 어떤 뭔가 불편하다는 이유로, 기반부터가 개반이니 뭐니 그런 소리를 하면, 기분이 나뻐서라도 그 소리를 외면하지 않겠나요?
분명히 자신이 생각하는게 맞고, 그게 좋으면 남한테 권할 수 도 있지만,
이렇게 과격한 방식으로는
받아들이는 이들은 소수 일것이고,
님의 좋은 의도와는 다르게
다수의 사람들 기분만 나뻐질 뿐입니다.
다음부터는 좀 더 덜 과격하게 전달해보는게
어떨까 합니다.
아무튼 글은 잘 읽었어요.
다른 사람이 본인의 생각을 존중해주길 바란다면
당사자인 자신부터, 다른 사람의 생각을 존중해주시고 최대한
과격하지 않게 했으면 합니다.
-php를 좋아하는 이가-
python이나 node js가 왜 고수준의 언어이지요?
고수준언어가 맞죠
닭잡을때 닭잡는 칼을 쓰고
소잡을때 소잡는 칼을 쓰고
프로그래머 자질을 논하다니 @.@
고수준 언어를 쓰래 ㅋㅋㅋㅋㅋ
애초에 엉망인 생태계에서 “나는 이 돼지우리가 좋아” 하고 있는 사람을 “좋은 프로그래머”라고는 부르기 힘들죠
고수준언어가 맞죠
분명한건 언어는 도구
쓰임새에 따라 효율적으로 이것저것 선택 사용하면 그만인걸
쉬운(저급 초보) 언어, 어려운(고급 순련자) 언어
쓰레기 언어, 좋은 언어
구분 짓고 고집 부리는 사람치고 개발능력 좋은 사람은 단 한명도 못봤네요
문제 해결 능력이 부족하면 그 언어에 불편함을 느낍니다
그러나 어떤 언어든 이슈가 있고 공부하고 대응 코딩하여 이슈를 해결하고 그 외 언어를 선택한 목적에 맞게 장점을 살리며 프로그래밍하는게 개발자의 능력이죠
아무리 뛰어난 언어가 탄생한다고 해도 개발자가 능력이 부족하면 그 결과물이 바로 쓰레기이지
언어는 쓰레기가 될 수는 없습니다
java 주력으로 si sm 파견 다니는 일부 인력들이 편견이 심한 경우가 있던데 혹시 글쓴님도 그쪽이신가요?
가볍게 망치가 필요할때 무겁게 해머가 필요할때가 있는 법입니다
진짜 개발자라면 어떤 도구든 아끼고 소중히 다뤄야겠죠
PHP의 문제는 쉬워서가 아니라 추상화 레이어가 정신이 나갔기 때문입니다.
당장 fopen() 콜이 URL을 리졸브해서 외래 리소스를 가져오는 것을 *좋은 아이디어* 라고 생각한 것 자체가 제대로 된 생각이 아닙니다.
더불어 일단 뭔가 이상해도 에러를 대충 씹어먹고 “어 뭔가 이상한데? 근데 아무것도 없는 것보단 뭐라도 있는 게 낫잖아?” 라는 정신으로 일단 돌리다가 신나게 0day 를 양산하는 것도 좋은 생각은 아니죠
덧: 살면서 SI SM 파견근무는 다행히도 가 본적이 없군요. 다만 깔끔하지 않은 설계, 특히 문제가 있어도 대충 문제를 무시하고 실행해서 온갖 보안 취약점을 일으키고 유지보수 지옥을 불러 일으키는 똥을 정말로 혐오하는 개발자일 뿐이죠.
취미로는 C, Rust, NodeJS, Elixir 쓰고 회사에서는 NodeJS, Elixir 씁니다.
웹 프로그래밍을 C언어로 짜는게 PHP 보다 정신력 코스트를 아낄 수 있다는 건 콤바인 대신 낫으로 벼베기를 하라는 것과 같습니다. (정작 C 언어로 웹 프로그래밍을 해 보신적은 있으신지 궁금합니다).
PHP 는 대충만들수도 제대로 만들 수도 있는 언어입니다. 졸작들도 멋진 기능을 수행합니다.
PHP 에 대한 공격은 배우기 쉽기 때문에 초보자도 웹 프로그래밍을 해서 기능을 수행하도록 만들기 쉽다는 점 때문에 발생합니다. 이것은 오히려 장점입니다.
고수의 경지에 이른다면, 난이도는 어느 분야나 비슷해 집니다만, 특별한 이유가 있지 않고서야 PHP를 놔두고 C 언어로 웹 프로그래밍을 하지는 않겠죠?
차라리 C로 짜라는 건 PHP보다 C가 차라리 *더* 일관적이라는 겁니다.
적어도 libc 의 함수들은 에러를 “씹어먹고” 이상하게 돌아가지는 않죠. libc 설정에 allow_url_fopen 같은 미친 플래그가 있지도 않고요
그리고 낮은 진입 장벽이 PHP의 똥을 만드는 데 유일한 원인은 절대 아닙니다. 엉망인 생태계와 엉망인 API 디자인, 그 외 문제들이 함께 시너지를 일으켜서 개판이 된 거죠.
낮은 진입장벽으로 유명한 ECMAScript(aka. JavaScript) 를 쓰는 NodeJS 를 보면, 생태계는 규모가 커짐에 따라 똥코드가 차오르기 시작했지만 복붙 코딩이 아닌(PHP 제대로 짜려는 사람 말고는 composer 안쓰잖아요) 애초부터 NPM 의존성으로 패키지가 관리된다는 점 때문에 공통 취약점 DB를 활용해 손쉽게 외래 코드 유래 문제에 대한 보고를 생성할 수 있으며 ECMAScript 표준 자체가 PHP 표준보다는 훨씬 튼튼하고(예: ECMAScript 의 foo.length 와 PHP count() 의 동작 차이를 보십시오) ES6을 지나 ES7, ESNext로 계속 발전해 나가며 언어 스펙 자체가 가지고 있던 더러운 부분들을 치워나가는 걸 보면 알 수 있죠.
언어는 도구다 님의 라라벨 써보셨나요가 답이네요 🙂
저는 저의 프로그래밍 의식 흐름에 맞질 않는다 생각해서 갈아 탔지만
모던 php와 라라벨의 노력 덕분에 깔 수가 없어요
그리고 당연히 의존성 관리 도구와 패키지 관리가 php도 잘 되고 있지요 🙂
아무래도 글을 수정해 주시면 좋을꺼 같네요
음 그리고 갑자기 궁금해 졌는데 php에도 이제 babel 같은 거 있으려나요 … 궁구밍
지금은 Node 개발자 올림
그런데 dart언어 때문에 구글은 까고 싶네요 ….