2013년 2월 25일 월요일

android - security tips

안드로이드 보안의 특징
 - 샌드박스는 다른 어플들에서 데이터 엑세스나 실행을 보호한다.
 - 암호화, 퍼미션, 안전한 IPC 등 일반적인 보안 특징을 제공한다.
 - 메모리 에러를 감소시키는 기술들을 제공한다.
 - 암호화된 파일시스템은 디바이스 분실시 데이터를 보호한다.
 - 사용자 동의의 퍼미션 기능은 사용자 데이터나 시스템 기능의 접근을 제한한다.
 - 어플별로 퍼미션을 설정하여 어플 데이터를 제어한다.

안드로이드는 위와 같은 보안 기능을 제공하나 부주의로 보안에 문제가 발생 할 수있으며, 다음과 보안관련 권고사항을 준수하여야 한다.


1. 데이터 저장
 안드로이드에서 보안 이슈는 대부분 데이터와 관련이 있으며 주요한 3가지 방식을 설명한다.

 1) 내부 저장소 사용
  - 기본적으로 안드로이드 내부 저장소는 자기 자신만이 엑세스 할 수 있다.
  - 일반적인 경우 MODE_WORLD_WRITEABLE, MODE_WORLD_READABLE 설정의 사용을 피해야 하며 만일 외부 어플에 데이터를 공유하고자 한다면 Content Provider를 사용해야 한다.
  - 중요한 데이터에 대한 추가적인 보안 기능 적용을 위해 어플에서 직접 엑세스 할 수 없는 키 데이터로 파일을 암호화한다.

 2) 외부 저장소 사용
  - SD Card와 같은 외부 저장소는 전역에서 읽고 쓰기가 가능하며 모든 어플에서 접근할 수 있기에 중요한 데이터는 저장하지 말아야 한다.
  - 실행파일이나 class를 저장하지 말고 동적로드로 코드를 실행하지 말아야 한다.
  - 만일 실행파일이나 class를 외부 저장소에서 읽어와 실행하고자 한다면 동적 로드전 검증을 해야한다.

 3) Content Provider 사용
  - 컨텐츠 프로바이더는 자신이나 외부 어플에 대해 제한된 접근을 할 수 있는 구조화된 기술을 제공한다.
  - android:exported 속성으로 외부 어플에서 데이터 엑세스를 허용 할 수 있다.
  - android:protectionLevel속성을 signature로 설정하면 같은 key로 signed된 어플만 엑세스 할 수 있게한다.
  - android:grantUriPermissions 속성과 Intent에 FLAG_GRANT_READ_URI_PERMISSION, FLAG_GRANT_WRITE_URI_PERMISSION flag 사용으로 일기/쓰기 제약을 할 수 있다.


2. 퍼미션 사용
 - 안드로이드는 샌드박스에 의해 제약이 가해져 있기에 카메라와 같은 디바이스 장치나 데이터에 엑세스 하기 위해서는 퍼미션을 명시하여야 한다.

 1) 퍼미션 요청
  - 보안을 위해 필요한 최소한의 퍼미션만 명시하길 권장한다.
  - 사용자 승인의 퍼미션 보단 접근 컨트롤의 사용을 권장한다.(위 1번 데이터 저장의 Content Provider 권한 설정같은)

 2) 퍼미션 생성
  일반적으로 정의된 퍼미션을 최소한으로 사용하여 구현하고 퍼미션의 생성은 다음 사항을 고려하여 신중히 검토 후 만들어야 한다.
  - 퍼미션은 사용자가 보안 항목이라 판단할 수 있는 간결한 문자열을 가져야 한다.
  - 퍼미션 문자열은 다국어를 지원해야 한다.
  - 사용자는 퍼미션이 혼란스럽거나 위험한 것으로 판단되면 설치하지 않을 것이다.
  - 퍼미션이 설치되지 않았다면 어플리케이션은 퍼미션을 요청할 것이다.


3. 네트워크 사용
 - 네트워크는 사용은 데이터를 전송하기에 본질적으로 위험을 내포하고 있다.

 1) IP 네트워크 사용
  - 안드로이드 네트워크는 리눅스와 크게 다르지 않으며 중요한 것은 중요한 데이터의 통신에 적절한 프로토콜을 사용하는 것이다.
  - 모바일 디바이스는 안전하지 않은 공개된 네트워크에 연결하는 경우가 많기에 Secure Socket을 사용하는 것을 권장한다.
  - 보안 상의 이유로 어플간에 localhost를 사용한 데이터 통신을 막았으며 대신 인증이 가능한 Service 같은것을 사용해야 한다.
  - 또한 WebView는 안전하지 않은 HTTP와 같은 프로토콜로 믿을 수 없는 데이터를 다운로드하는 것을 막는 유효성 체크 기능을 제공한다.

 2) 전화 통신 사용
  - SMS는 사용자간 연락을 주 용도로 설계되어 데이터 통신에는 적합하지 않다.
  - SMS의 제약으로 데이터 통신은 Google Cloud Messaging이나 Web 기반의 IP 네트워크를 사용하길 권한다.
  - SMS는 암호화되지도 않으며 강력한 인증을 사용하지도 않는다.
  - 네트워크 상에서 spoofing이나 interception의 대상이 될 수 있다.
  - READ_SMS 퍼미션을 갖는 다른 어플에 의해 수신될 수 있다.


4. Input Validation 수행
 - 안드로이드는 플랫폼 레벨에서 Input Validation에 대응할 수단을 갖추고 있고 이를 잘 활용해야 한다.
 - 만일 Native를 코드를 사용해서 파일이나 네트워크 입/출력을 한다면 노출에 대한 잠재적 위험을 안고 있으며 대부분의 문제는 buffer overflows, use after free, off-by-one errors  등이며 안드로이드는 ASLR, DEP등 문제를 감소시킬 많은 기술을 제공하지만 충분하지 않으며 포인터나 버퍼의 사용에 주의해야 한다.
 - JavaScript, SQL과 같은 문자열 기반의 언어는 escape characters, script injection 등의 문제를 안고 있다.
 - SQL의 경우는 Content Provider를 이용해 parameterized queries방식을 지원하는 것이 이상적이다. (쓰기 권한이 필요없는 데이터는 읽기 권한만 부여한다.)
 - 만일 위와 같은 보안기능을 사용할 수 없다면 데이터를 구조화 시키고 이에 대한 유효성을 체크하는 기능을 부여하라. (데이터 변조를 감지할 수 있는)


5. 사용자 데이터 다루기
 - 사용자 정보와 같은 민감한 데이터에 API 사용을 최소화 하고 사용할 수밖에 없다면 Hash나 non-reversible form을 사용해라.(메모리 덤프 등으로 노출될 가능성을 줄임)
 - 네트워크 전송이나 공유된 저장소에 저장하는것을 피하라.
 - 사용자 정보에 대한 키값으로 폰번호나 IMEI 등을 사용하지 마라.
 - 로그를 남길때 주의하라. READ_LOGS 권한을 갖는 어플도 함께 읽을 수 있다.


6. WebView 사용
 - WebView는 HTML이나 JavaScript와 같은 컨텐츠를 처리하기에 cross-site-scripting(JavaScript Injection)과 같은 웹 보안 이슈에 노출될 수 있다.
 - WebView는 기본적으로 JavaScript를 실행할 수 없으며 컨텐츠에서 JavaScript를 사용하지 않는다면 setJavaScriptEnabled() 호출하지 마라.
 - addJavascriptInteface()를 사용할때 주의해야 한다. 신뢰할 수 없는 스크립트 실행으로 안드로이드 메소드가 실행될 수 있다.
 - local에 저장된 파일을 삭제하기 위해 clearCache() 메소드를 사용할 수 있다.
 - Server에서 헤더에 no-cache옵션을 사용할 수 있다.


7. 자격증명 다루기
 - 일반적으로 자격증명 요청시도를 최소화 하라
 - 사용자명이나 암호를 로컬에 저장하여 인증에 사용하지 말고, 다수 어플에서 사용시 AccountManager를 이용해라.
 - 단일 어플에서만 사용하고자 한다면 KeyStore를 사용해라.


8. 암호화 사용
 - 파일시스템 암호화, 안전한 소켓 채널 등에 더불어 안드로이드는 암호화를 사용한 데이터 보호기능을 제공한다.
 - 안전한 네트워크 통신을 위해 자체 구현된 암호화 기술보단 HttpsURLConneciton이나 SSLSocket을 사용하길 권한다.
 - 암호화 알고리즘을 직접 구현하기 보단 Cipher에서 제공하는 AES, RSA 등을 사용하길 권한다.
 - 암호화 알고리즘에 사용하는 키를 생성시 SecureRandom은 그리 안전하지 않으며 KeyGenerator를 사용하길 권한다.


9. 프로세스 내 통신
 - 일부 어플들은 localhost 소켓, 공유 파일 등전통적인 리눅스 기술을 사용하여 IPC를 구현하였으나 안드로이드에서는 Service와 BroadcastReceiver로 Intent, Binder, Messenger 를 이용하여 안전한 IPC를 구현할 수 있다.
 - 만일 다른 어플에게까지 확장시키지 않으려면 <service> 태그에 android:exported 속성을 false로 주면된다.(이 옵션은 하나의 UID에 다수 프로세스를 사용하는 어플에 유용하다)
 - 다른 어플들에게까지 확장하여 사용한다면 퍼미션을 지정하여 보안정책을 적용할 수 있다.(android:protectionLevel 속성을 signature로 지정하여 같은 key로 signed된 어플들만 허용할 수 있음)


10. Intent 사용
 - Intent는 안드로이드에서 비동기적인 IPC 구현에 사용된다.
 - sendOrderedBroadcast()는 수신자에 의해 소비되어 하나의 수신자만이 받을 수 있다. 퍼미션을 함께 적용하면 꼭 받아야할 하나의 수신자가 받게된다.


11. 서비스 사용
 - 서비스는 종종 다른 어플에게 기능을 제공하기 위해 사용된다.
 - 서비스는 기본적으로 다른 어플에게 확장되지 않는다.
 - <service> 태그에 IntentFilter를 추가하면 기본적으로 다른 어플에게까지 확장된다.
 - android:exported 속성으로 명시적으로 다른 어플에게 확장됨을 지정할 수 있다.
 - 서비스 요청이 왔을때 실행전 checkCallingPermission()으로 퍼미션을 체크할 수 있으나 manifest에 명시적으로 퍼미션을 선언하는 것을 권한다.

 1) Binder와 Messenger 인터페이스 사용
  - 안드로이드에서 RPC 형태의 IPC 구현에 사용된다.
  - 해당 인터페이스를 위한 별도의 퍼미션 설절은 필요하지 않으며 구현된 Activity놔 Service의 퍼미션을 따른다.
 2) BroadcastReceiver 사용
  - Intent에 의한 요청을 비동기적으로 처리한다.


12. 코드의 동적 로딩
 - APK 밖의 코드를 동적 로드하는것을 권하지 않는다.
 - 다운로드된 코드나 SD Card에 존재하는 코드를 동적로드 하는 것은 매우 위험하며 불가피하게 사용해야 한다면 암호화나 위변조방지 기술을 사용해야 한다. (디바이스에서 제공하는 내부 저장공간의 부족등의 이유로 불가피하게 사용하는 경우가 있음)


13. 가상머신에서 보안
 - 안드로이드에서 사용하는 dalvik 또한 다른 가상머신에서 제공하는 보안 코드를 제공하고 있다.
 - 어플을 개발할때 가상머신과 관련해서 보안에 특이하게 고려할 필요는 없다.
 - 안드로이드에서 제공하는 Sandbox는 가상머신이 아닌 OS레벨에서 제공하는 기능으로 Native코드나 dalvik 모두에게 적용된다.


14. Native 코드에서 보안
 - 일반적으로 NDK를 이용한 Native 코드의 사용보단 SDK의 사용을 권장한다.
 - 만일 Native 코드를 개발하고자 한다면 안드로이드는 Linux 커널 기반으로 만들어졌기에 리눅스 개발을 위한 보안 가이드라인을 따르길 바란다.
 - 안드로이드와 리눅스의 가장 큰 차이는 Sandbox이며 Native 코드를 포함한 안드로이드 어플은 Sandbox 안에서 실행된다.


참고 URL)

http://developer.android.com/training/articles/security-tips.html

http://www.securingjava.com/toc.html

http://www.dwheeler.com/secure-programs/

댓글 없음:

댓글 쓰기