PHP 이미지 업로드 보안 검사 목록
내 응용 프로그램에 이미지를 업로드하는 스크립트를 프로그래밍하고 있습니다. 다음 보안 단계로 스크립트 측에서 애플리케이션을 안전하게 만들 수 있습니까?
- .httaccess를 사용하여 업로드 폴더 내에서 PHP가 실행되지 않도록합니다.
- 파일 이름에 "php"문자열이 포함 된 경우 업로드를 허용하지 않습니다.
- 확장자 만 허용 : jpg, jpeg, gif 및 png.
- 이미지 파일 형식 만 허용합니다.
- 파일 형식이 두 개인 이미지를 허용하지 않습니다.
- 이미지 이름을 변경하십시오.
- 루트 디렉터리가 아닌 하위 디렉터리에 업로드합니다.
이것은 내 스크립트입니다.
$filename=$_FILES['my_files']['name'];
$filetype=$_FILES['my_files']['type'];
$filename = strtolower($filename);
$filetype = strtolower($filetype);
//check if contain php and kill it
$pos = strpos($filename,'php');
if(!($pos === false)) {
die('error');
}
//get the file ext
$file_ext = strrchr($filename, '.');
//check if its allowed or not
$whitelist = array(".jpg",".jpeg",".gif",".png");
if (!(in_array($file_ext, $whitelist))) {
die('not allowed extension,please upload images only');
}
//check upload type
$pos = strpos($filetype,'image');
if($pos === false) {
die('error 1');
}
$imageinfo = getimagesize($_FILES['my_files']['tmp_name']);
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
die('error 2');
}
//check double file type (image with comment)
if(substr_count($filetype, '/')>1){
die('error 3')
}
// upload to upload direcory
$uploaddir = 'upload/'.date("Y-m-d").'/' ;
if (file_exists($uploaddir)) {
} else {
mkdir( $uploaddir, 0777);
}
//change the image name
$uploadfile = $uploaddir . md5(basename($_FILES['my_files']['name'])).$file_ext;
if (move_uploaded_file($_FILES['my_files']['tmp_name'], $uploadfile)) {
echo "<img id=\"upload_id\" src=\"".$uploadfile."\"><br />";
} else {
echo "error";
}
새로운 팁은 환영합니다 :)
GD (또는 Imagick)를 사용하여 이미지를 다시 처리하고 처리 된 이미지를 저장합니다. 다른 모든 것은
해커에게
재미 있고
지루합니다.
편집 : 그리고 rr이 지적했듯이 move_uploaded_file()
모든 업로드에 사용 하십시오.
늦은 편집 : 그건 그렇고, 업로드 폴더에 대해 매우 제한하고 싶을 것입니다. 이러한 장소는 많은 악용이 발생하는 어두운 구석 중 하나입니다. 이는 모든 유형의 업로드 및 모든 프로그래밍 언어 / 서버에 유효합니다. https://www.owasp.org/index.php/Unrestricted_File_Upload 확인
이미지 파일의 보안 테스트를 위해 4 단계의 증권을 생각할 수 있습니다. 다음과 같습니다.
- 레벨 1 : 확장자 확인 (확장 파일은 다음으로 끝남)
- 레벨 2 : MIME 유형 확인
($file_info = getimagesize($_FILES['image_file']; $file_mime = $file_info['mime'];)
- 레벨 3 : 처음 100 바이트를 읽고 ASCII 0-8, 12-31 (10 진수) 범위의 바이트가 있는지 확인합니다.
- 레벨 4 : 헤더에서 매직 넘버를 확인합니다 (파일의 처음 10-20 바이트). http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Examples 에서 일부 파일 헤더 바이트를 찾을 수 있습니다 .
참고 : 전체 이미지를로드하는 속도가 느립니다.
XSS 경고
한 가지 더 중요한 발언. 브라우저에서 HTML로 해석 될 수있는 것은 제공 / 업로드하지 마십시오.
파일이 귀하의 도메인에 있기 때문에 해당 HTML 문서에 포함 된 javascript는 귀하의 모든 쿠키에 액세스하여 일종의 XSS 공격을 가능하게합니다.
공격 시나리오 :
공격자는 모든 쿠키를 자신의 서버로 보내는 JS 코드가 포함 된 HTML 파일을 업로드합니다.
공격자는 메일, PM 또는 단순히 자신이나 다른 사이트의 iframe을 통해 사용자에게 링크를 보냅니다.
가장 안전한 솔루션 :
업로드 된 콘텐츠는 하위 도메인 또는 다른 도메인에서만 사용할 수 있습니다. 이렇게하면 쿠키에 액세스 할 수 없습니다. 이것은 또한 Google의 성능 팁 중 하나입니다.
https://developers.google.com/speed/docs/best-practices/request#ServeFromCookielessDomain
$ _FILES [ 'my_files'] [ 'tmp_name']에서도 "is_uploaded_file"을 실행할 수 있습니다. http://php.net/manual/en/function.is-uploaded-file.php 참조
업로드 디렉토리에 새 .htaccess 파일을 만들고 다음 코드를 붙여 넣습니다.
php_flag engine 0
RemoveHandler .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
AddType application/x-httpd-php-source .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml
업로드 한 파일의 이름을 변경하고 유형, 내용 등을 확인하는 것은 잊어 버리십시오.
관련 질문에 게시 한 내용을 반복하겠습니다.
Fileinfo 함수 (이전 버전의 PHP에서는 mime_content_type ())를 사용하여 콘텐츠 유형을 감지 할 수 있습니다 .
이전 Mimetype 확장에 대한 발췌 양식 PHP 매뉴얼, 이제 Fileinfo로 대체되었습니다.
이 모듈의 함수는 파일 내의 특정 위치에서 특정 매직 바이트 시퀀스를 찾아 파일의 내용 유형과 인코딩을 추측합니다. 이것이 방탄 접근 방식은 아니지만 사용 된 휴리스틱은 아주 좋은 일을합니다.
getimagesize()
좋은 일을 할 수도 있지만 수행하는 다른 검사의 대부분은 말도 안됩니다. 예를 들어 php
파일 이름에 문자열 이 허용되지 않는 이유 . 이름에 php
문자열이 포함되어 있기 때문에 PHP 스크립트 내에 이미지 파일을 포함하지 않을 것입니다 .
이미지를 다시 만들 때 사용하는 라이브러리가 취약하지 않을 때까지 대부분의 경우 보안이 향상됩니다.
그렇다면 안전한 이미지 재생성에 가장 적합한 PHP 확장은 무엇입니까? CVE 세부 정보 웹 사이트를 확인했습니다 . 적용 가능한 트리오는 이러한 확장이라고 생각합니다.
- GD (6 가지 취약점)
- ImageMagick (44 가지 취약점)
- Gmagick (12 가지 취약점)
비교에서 GD는 보안 문제가 가장 적고 꽤 오래 되었기 때문에 가장 적합하다고 생각합니다. 그중 3 개가 중요하지만 ImagMagick과 Gmagick은 더 나은 성능을 발휘하지 못합니다. ImageMagick은 매우 버그가 많은 것 같습니다 (적어도 보안에 관해서는). 그래서 저는 Gmagick을 두 번째 옵션으로 선택했습니다.
보안이 매우 중요한 경우 저장 파일 이름과 이름이 변경된 파일 이름에 데이터베이스를 사용하고 여기에서 파일 확장자를 .myfile과 같은 것으로 변경하고 헤더가있는 이미지를 보내기위한 PHP 파일을 만들 수 있습니다. php는 더 안전 할 수 있으며 blow와 같은 img 태그에서 사용할 수 있습니다.
<img src="send_img.php?id=555" alt="">
업로드하기 전에 EXIF로 파일 확장자도 확인하십시오.
The simplest answer to allow users to securely upload files in PHP is: Always save files outside of your document root.
For example: If your document root is /home/example/public_html
, save files to /home/example/uploaded
.
With your files safely out of the confines of being directly executed by your web server, there are a couple of ways you can still make them accessible to your visitors:
- Set up a separate virtual host for serving static content which never executes PHP, Perl, etc. scripts.
- Upload the files to another server (e.g. a cheap VPS, Amazon S3, etc).
- Keep them on the same server, and use a PHP script to proxy requests to ensure the file is only ever readable, not executable.
However, if you go with options 1 or 3 on this list and you have a local file inclusion vulnerability in your application, your file upload form can still be an attack vector.
The best way to keep your website secure when user upload image is to do this steps :
- check the image extension
- check the image size with this function "getimagesize()"
- after this you can use the function "file_get_contents()"
- In the end you should insert file_Content to your database i think that's the best way ! nd what's your opinion ?
For an image file, you could also change file permission after renaming to be sure it never executes (rw-r--r--)
I'm using a php-upload-script that creates a new random 4-byte-number for each uploaded file, then XORs the content of the file with these 4 bytes (repeating them as often as necessary), and finally attaches the 4 bytes to the file before saving it.
For downloading, the 4 bytes have to be cut off of the file again, the contents will be XORed with them again and the result is sent to the client.
This way, I can be sure that the files I save on the server will not be executable or have any potential meaning whatsoever for any application. Plus I don't need any extra database to store filenames in.
Here is the code I'm using for this:
Upload:
<?php
$outputfilename = $_POST['filename'];
$inputfile = $_FILES["myblob"]["tmp_name"];
$tempfilename="temp.tmp";
if( move_uploaded_file($inputfile, $tempfilename) ) {
$XORstring = random_bytes(4);
$tempfile=fopen($tempfilename, "r");
$outputfile=fopen($outputfilename, "w+");
flock($outputfilename, LOCK_EX);
fwrite($outputfilename, $XORbytes1);
while ( $buffer = fread($tempfile, 4) ) {
$buffer = $buffer ^ $XORstring;
fwrite($outputfilename, $buffer);
}
flock($outputfilename, LOCK_UN);
fclose($tempfile);
fclose($outputfile);
unlink($tempfilename);
}
exit(0);
?>
Download:
<?php
$inputfilename = $_POST['filename'];
$tempfilename = "temp.tmp";
$inputfile=fopen($inputfilename, "r");
$tempfile=fopen($tempfilename, "w+");
flock($tempfile, LOCK_EX);
$XORstring = fread($inputfile, 4);
while ( $buffer = fread($inputfile, 4) ) {
$buffer = $buffer ^ $XORstring;
fwrite($tempfile, $buffer);
}
flock($tempfile, LOCK_UN);
fclose($inputfile);
fclose($tempfile);
readfile($tempfile);
unlink($tempfile);
exit(0);
?>
참고URL : https://stackoverflow.com/questions/4166762/php-image-upload-security-check-list
'Programing' 카테고리의 다른 글
MismatchSenderId를받는 FCM (0) | 2020.12.02 |
---|---|
WPF XAML StringFormat DateTime : 잘못된 문화권의 출력? (0) | 2020.12.02 |
Android : 버튼 텍스트 및 배경색 변경 (0) | 2020.12.01 |
동일한 클래스의 다른 버전에 대한 플레이버 빌드 (0) | 2020.12.01 |
Travis-CI를 구성하여 풀 리퀘스트를 빌드하고 중복없이 마스터에 병합하는 방법 (0) | 2020.12.01 |