2011-10-03 24 views
24

Chúng tôi đang xây dựng một trò chơi cho Android, cần truy cập vào các dịch vụ web - vì vậy chúng tôi đã viết một API RESTful trong PHP chạy trên máy chủ của chính chúng tôi. API cung cấp là gì: tạo người dùng, đăng nhập, tải xuống trò chơi, truy xuất danh sách trò chơi, gửi số điểm ... v.v. Bây giờ tôi đang nghĩ, nếu một số người dùng có kinh nghiệm có định dạng URL của API - s/ông sẽ có thể vào thùng rác hệ thống bằng nhiều cách:bảo mật API REST có thể truy cập được từ Android

  • tạo một kịch bản chạy & nó để tạo người dùng tự động - tôi nghĩ rằng tôi có thể ngăn chặn nó bằng cách CAPTCHA hoặc someting như thế. Nhưng một lần nữa, captcha sẽ làm phiền người chơi trò chơi.
  • Nhật ký người dùng độc hại khi sử dụng trình duyệt của mình, tải xuống trò chơi & sau đó gửi điểm số theo ý muốn - tất cả bằng cách gọi API bằng cách chỉ cần nhập từ trình duyệt của mình. Tôi cho rằng người dùng độc hại bằng cách nào đó biết các url API để gọi - bằng cách đánh hơi khi ứng dụng đang thực hiện các yêu cầu HTTP.
  • Tôi cần đảm bảo rằng các yêu cầu chỉ được thực hiện từ thiết bị Android đã cài đặt trò chơi. (Trò chơi sẽ được miễn phí)

Bây giờ Làm cách nào để ngăn chặn những hành vi lạm dụng như vậy?

Trả lời

27

Tôi nghĩ rằng bạn sẽ không bao giờ có thể che giấu các url được gọi bởi ứng dụng (nếu tôi đang chạy một chiếc điện thoại gốc-ed android, tôi sẽ có thể để làm gián điệp trên tất cả các lưu lượng mạng)

Nhưng bạn vấn đề thực sự là bạn cần phải xác thực api của bạn theo một cách nào đó.

Có một cách để triển khai OAUTH, nhưng có thể điều này là quá mức cần thiết.

Nếu bạn muốn có một cơ chế đơn giản, cách thức này;

  1. tạo ra một khóa bí mật
  2. xây dựng theo yêu cầu api (ví dụ. https://my.example.com/users/23?fields=name,email)
  3. băm yêu cầu con đường này + cộng với khóa bí mật của bạn (ví dụ. Md5 (url + secret_key) == "a3c2fe167")
  4. thêm băm này để yêu cầu của bạn (bây giờ nó là https://.....?fields=name,email&hash=a3c2fe167)
  5. vào cuối api, thực hiện chuyển đổi tương tự (loại bỏ các param băm)
  6. check md5 của url và khóa bí mật

Miễn là bí mật vẫn bí mật, không ai có thể giả mạo yêu cầu của bạn.

Ví dụ (trong pseudo-code):

phía Android:

SECRET_KEY = "abc123" 

def call_api_with_secret(url, params) 
    # create the hash to sign the request 
    hash = MD5.hash(SECRET_KEY, url, params) 

    # call the api with the added hash 
    call_api(url+"&hash=#{hash}", params) 
end 

Server side:

SECRET_KEY = "abc123" 

def receive_from_api(url, params) 
    # retrieve the hash 
    url_without_hash, received_hash = retrieve_and_remove_hash(url) 

    # check the hash 
    expected_hash = MD5.hash(SECRET_KEY, url_without_hash, params) 

    if (expected_hash != received_hash) 
    raise our exception! 
    end 

    # now do the usual stuff 
end 
+1

Cảm ơn bạn rất nhiều, @ matthew-rudy :) Tôi có tạo 'khóa bí mật' cho mỗi người dùng không? Nếu sau đó, làm cách nào để phân phối nó? Nếu tôi gửi khóa bí mật cho ứng dụng sau khi đăng ký làm phản hồi, người ta có thể thực hiện cuộc gọi API đơn giản từ trình duyệt trên máy tính để bàn của mình và nhận khóa bí mật làm phản hồi. – giga

+6

Trong cách tiếp cận của Matthew, khóa bí mật không bao giờ được gửi qua dây. Đó là "muối" được thêm vào url để tạo băm. Vì hàm băm là hàm một chiều nên người dùng không thể khôi phục khóa bí mật từ hàm băm. Nó sẽ yêu cầu người dùng dịch ngược APK và xem xét mã nguồn để tìm khóa. Bạn có thể sử dụng các kỹ thuật mã hóa để làm cho điều này trở nên khó khăn hơn, nhưng nó sẽ luôn luôn có thể cho một người nào đó tìm ra chìa khóa, cho đủ thời gian và động lực. –

+3

thực sự là @JasonLeBrun, tôi đã thêm một ví dụ giả mã. Nhưng, giga, tôi đề nghị bạn tìm kiếm một khung công tác hiện có trong PHP, thay vì tạo ra khung của riêng bạn. Tôi chắc chắn phải có nhiều giải pháp hiện có. –

1

Nếu bạn thực sự muốn bảo mật kết nối sau đó bạn sẽ phải sử dụng mật mã khóa công khai, vd RSA. Thiết bị sẽ mã hóa thông tin đăng nhập bằng khóa công khai và ở cuối máy chủ, bạn sẽ phải giải mã bằng khóa riêng. Sau khi đăng nhập, máy chủ sẽ gửi một mã thông báo/mã hóa (phản hồi sẽ là một JSON được mã hóa hoặc một cái gì đó) và thiết bị sẽ lưu trữ nó.Từ đó, miễn là phiên không hết hạn, thiết bị sẽ gửi tất cả thông tin được mã hóa bằng mã thông báo đó. Đối với các yêu cầu này, bạn không nên sử dụng nguyên nhân RSA sẽ mất nhiều thời gian hơn. Bạn có thể sử dụng AES256 (mã hóa khóa riêng tư phổ biến) với khóa mã hóa nhận được từ máy chủ để mã hóa các yêu cầu của bạn.

Vì mục đích đơn giản, bạn có thể xóa hoàn toàn RSA (Nếu bạn không gửi thông tin thanh toán) và thực hiện mọi thứ bằng AES256 bằng khóa riêng. Các bước phải là -

  • Mã hóa mọi yêu cầu gửi đi bằng khóa cá nhân.
  • Chuyển đổi chuỗi được mã hóa thành chuỗi 64 cơ sở.
  • URL mã hóa chuỗi được mã hóa cơ sở 64.
  • Gửi nó qua.

Trên máy chủ cuối

  • Đỗ cơ sở 64 decode
  • Decrypt bằng cách sử dụng khóa riêng.

Yêu cầu của bạn phải mang chữ ký (ví dụ: khóa mã hóa được thêm vào dưới dạng muối) để có thể nhận dạng nó sau khi giải mã. Nếu chữ ký không có mặt chỉ đơn giản là loại bỏ yêu cầu.

Để gửi phản hồi giống nhau.

SDK Android nên có phương pháp mã hóa bằng mã hóa AES256 và Base 64.

+0

Làm thế nào tốt hơn sau đó là HTTPS? –

+0

Tôi chưa bao giờ nói rằng nó sẽ như thế. Đó là giải pháp nếu bạn không có Chứng nhận HTTPS. – rushafi

+0

Bạn có thể có chứng chỉ tự ký với HTTPS, nếu bạn không muốn mua chứng chỉ từ một CA cho một vài đô la. Bạn cũng đang đề xuất một giải pháp khóa riêng tư vì vậy đây là kỹ thuật giống nhau, khó thực hiện hơn nhiều. –

3

Bạn đã đề cập đến người dùng giả mạo điểm số cao. Điều này vẫn có thể xảy ra nếu người dùng của bạn được xác thực. Khi trò chơi đang tải lên điểm số cao, bạn có thể muốn có nó cũng tải lên một bằng chứng về điểm số. Ví dụ Điểm 20100 từ 103 lỗi squished, 1200 dặm bay, cấp 3 đạt được, và 2 anh đào đã được ăn. Điều này là không có nghĩa là hoàn hảo nhưng sẽ bao gồm các quả treo thấp.

Việc đầu tiên bạn nên làm là có người dùng được xác thực. Userid/mật khẩu/session token vv, xem nếu bạn có thể tìm thấy một số framework đã tồn tại. Khi bạn đã xác thực người dùng, hãy đảm bảo rằng bạn có thể thực hiện điều đó một cách an toàn với TLS hoặc tương tự.

Theo tôi biết không có cách nào máy chủ của bạn có thể chắc chắn rằng yêu cầu đến từ ứng dụng của bạn (tất cả chỉ là bit trong gói) nhưng ít nhất bạn cũng có thể khiến người khác trở nên khó khăn.

  • Xây dựng một bí mật vào ứng dụng của bạn (theo đề nghị của phản ứng khác, chìa khóa, muối băm, vv)
  • Tạo một ID duy nhất trên thực hiện đầu tiên của ứng dụng sau khi cài đặt và theo dõi rằng cùng với sự đăng nhập người dùng. Thông tin chi tiết về vấn đề này và ID duy nhất của thiết bị (tại sao không sử dụng nó) có thể được tìm thấy trên android blog
  • Một số ý tưởng đã thảo luận trong bài viết này How to ensure/determine that a post is coming from an specific application running on an iPhone/iTouch?
  • Kiểm tra User Agent
+0

Cảm ơn bạn đã bình luận. Thay vì tải lên tổng số điểm, tách nó thành các phần âm thanh ít gây hại. – giga

+0

@giga Nó không chỉ là sự chia tách. Bạn muốn họ gửi điểm số, và bằng chứng rằng điểm số được gửi được tạo ra bởi một cái gì đó mà biết làm thế nào điểm số làm việc (ứng dụng của bạn sẽ biết điều này).Nếu bạn chỉ chia nó, thì người dùng độc hại vẫn có thể gửi các giá trị tùy ý. Bạn muốn buộc họ phải đảo ngược kỹ sư ứng dụng của bạn chứ không phải chỉ là lấy thông tin liên lạc. – goldsz

7

Giải pháp mà người khác đã trình bày ở đây là được gọi là security through obscurity. Về cơ bản họ đang cố gắng che khuất giao thức và ẩn việc triển khai. Điều này có thể hoạt động cho đến khi ai đó đủ khả năng tháo gỡ ứng dụng và kỹ sư đảo ngược giao thức. Tin tặc rất có khả năng ở đó.

Câu hỏi đặt ra là liệu ứng dụng của bạn có đáng bị nứt không? Các chương trình như iTunes, DVD hoặc mạng Sony PS3 rõ ràng là đáng để thử. Cách tiếp cận tối nghĩa có thể hoạt động nếu không ai có khả năng bẻ khóa. Chỉ cần không đánh lừa bản thân rằng nó không phải là doeable.

Vì bạn không thể tin tưởng thiết bị hoặc ứng dụng của mình, bạn phải tin tưởng người dùng. Để tin tưởng người dùng, bạn cần hệ thống nhận dạng và ủy quyền người dùng. Về cơ bản, đăng nhập vào ứng dụng của bạn. Thay vào đó, bạn cuộn hệ thống riêng của mình (đăng nhập bằng email xác nhận, v.v.), sử dụng hệ thống của bên thứ 3: OpenID (tài khoản google) hoặc OAuth (facebook, twitter). Trong trường hợp facebook sử dụng lược đồ auth phía máy chủ.

Những gì tôi muốn làm:

  1. Cho phép người dùng tự do chơi các trò chơi cho đến khi họ muốn "cứu" các kết quả trên máy chủ.
  2. Trước khi lưu kết quả, chúng có thể đăng nhập thông qua phương pháp được đề cập ở trên.
  3. Sử dụng HTTPS để gửi dữ liệu đến máy chủ của bạn. Mua chứng chỉ ssl từ CA đáng tin cậy, vì vậy bạn không phải xử lý các chứng chỉ tự ký.
1

Làm theo nhóm these guidelines từ nhóm Android để bảo vệ chương trình phụ trợ của bạn bằng cách sử dụng mã thông báo Oauth được cung cấp qua API của Google.

Các vấn đề liên quan