跳过内容

MASTG-DEMO-0009: 检测网络流量中的敏感数据

下载 MASTG-DEMO-0009 APK 打开 MASTG-DEMO-0009 文件夹 构建 MASTG-DEMO-0009 APK

示例

下面的代码片段展示了使用 HttpURLConnection 类通过网络发送敏感数据的示例代码。 这些数据被发送到 https://httpbin.org/post,这是一个虚拟端点,用于返回它接收到的数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package org.owasp.mastestapp

import android.content.Context
import android.util.Log
import java.io.BufferedOutputStream
import java.io.BufferedWriter
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import java.util.logging.Logger

class MastgTest (private val context: Context){

    fun mastgTest(): String { 

        val SENSITIVE_DATA = mapOf(
            "precise_location_latitude" to "37.7749",
            "precise_location_longitude" to "-122.4194",
            "name" to "John Doe",
            "email_address" to "[email protected]",
            "phone_number" to "+11234567890",
            "credit_card_number" to "1234 5678 9012 3456"
        )

        var result = ""

        val thread = Thread {
            try {
                val url = URL("https://httpbin.org/post")
                val httpURLConnection = url.openConnection() as HttpURLConnection
                httpURLConnection.requestMethod = "POST"
                httpURLConnection.doOutput = true
                httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")

                // Creating POST data from the SENSITIVE_DATA map
                val postData = SENSITIVE_DATA.map { (key, value) ->
                    "${URLEncoder.encode(key, "UTF-8")}=${URLEncoder.encode(value, "UTF-8")}"
                }.joinToString("&")

                val outputStream = BufferedOutputStream(httpURLConnection.outputStream)
                val bufferedWriter = BufferedWriter(OutputStreamWriter(outputStream, "UTF-8"))
                bufferedWriter.write(postData)
                bufferedWriter.flush()
                bufferedWriter.close()
                outputStream.close()

                val responseCode = httpURLConnection.responseCode
                val responseContent = httpURLConnection.inputStream.bufferedReader().readText()
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    Log.d("HTTP_SUCCESS", "Successfully authenticated.")
                } else {
                    Log.e("HTTP_ERROR", "Failed to authenticate. Response code: $responseCode")
                }
                result = "$responseCode\n\n$responseContent"

            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        thread.start()
        thread.join()

        return result
    }

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package org.owasp.mastestapp;

import android.content.Context;
import android.util.Log;
import androidx.autofill.HintConstants;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import kotlin.Metadata;
import kotlin.TuplesKt;
import kotlin.collections.CollectionsKt;
import kotlin.collections.MapsKt;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.Ref;

/* compiled from: MastgTest.kt */
@Metadata(d1 = {"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u0007"}, d2 = {"Lorg/owasp/mastestapp/MastgTest;", "", "context", "Landroid/content/Context;", "(Landroid/content/Context;)V", "mastgTest", "", "app_debug"}, k = 1, mv = {1, 9, 0}, xi = 48)
/* loaded from: classes4.dex */
public final class MastgTest {
    public static final int $stable = 8;
    private final Context context;

    public MastgTest(Context context) {
        Intrinsics.checkNotNullParameter(context, "context");
        this.context = context;
    }

    /* JADX WARN: Multi-variable type inference failed */
    public final String mastgTest() {
        final Map SENSITIVE_DATA = MapsKt.mapOf(TuplesKt.to("precise_location_latitude", "37.7749"), TuplesKt.to("precise_location_longitude", "-122.4194"), TuplesKt.to(HintConstants.AUTOFILL_HINT_NAME, "John Doe"), TuplesKt.to("email_address", "[email protected]"), TuplesKt.to("phone_number", "+11234567890"), TuplesKt.to("credit_card_number", "1234 5678 9012 3456"));
        final Ref.ObjectRef result = new Ref.ObjectRef();
        result.element = "";
        Thread thread = new Thread(new Runnable() { // from class: org.owasp.mastestapp.MastgTest$$ExternalSyntheticLambda0
            @Override // java.lang.Runnable
            public final void run() {
                MastgTest.mastgTest$lambda$1(SENSITIVE_DATA, result);
            }
        });
        thread.start();
        thread.join();
        return (String) result.element;
    }

    /* JADX INFO: Access modifiers changed from: private */
    /* JADX WARN: Type inference failed for: r7v10, types: [T, java.lang.String] */
    public static final void mastgTest$lambda$1(Map SENSITIVE_DATA, Ref.ObjectRef result) {
        Intrinsics.checkNotNullParameter(SENSITIVE_DATA, "$SENSITIVE_DATA");
        Intrinsics.checkNotNullParameter(result, "$result");
        try {
            URL url = new URL("https://httpbin.org/post");
            URLConnection openConnection = url.openConnection();
            Intrinsics.checkNotNull(openConnection, "null cannot be cast to non-null type java.net.HttpURLConnection");
            HttpURLConnection httpURLConnection = (HttpURLConnection) openConnection;
            httpURLConnection.setRequestMethod("POST");
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            Collection destination$iv$iv = new ArrayList(SENSITIVE_DATA.size());
            for (Map.Entry item$iv$iv : SENSITIVE_DATA.entrySet()) {
                String key = (String) item$iv$iv.getKey();
                String value = (String) item$iv$iv.getValue();
                destination$iv$iv.add(URLEncoder.encode(key, "UTF-8") + '=' + URLEncoder.encode(value, "UTF-8"));
                url = url;
            }
            String postData = CollectionsKt.joinToString$default((List) destination$iv$iv, "&", null, null, 0, null, null, 62, null);
            BufferedOutputStream outputStream = new BufferedOutputStream(httpURLConnection.getOutputStream());
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
            bufferedWriter.write(postData);
            bufferedWriter.flush();
            bufferedWriter.close();
            outputStream.close();
            int responseCode = httpURLConnection.getResponseCode();
            if (responseCode == 200) {
                Log.d("HTTP_SUCCESS", "Successfully authenticated.");
            } else {
                Log.e("HTTP_ERROR", "Failed to authenticate. Response code: " + responseCode);
            }
            result.element = responseCode + "\n\n" + postData;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

步骤

启动设备,在本例中为 Android 模拟器

emulator -avd Pixel_3a_API_33_arm64-v8a -writable-system

运行 mitmproxy,并使用自定义脚本来记录敏感数据,并将相关流量转储到文件中。

请注意,该脚本已预先配置了此应用程序已视为敏感的数据。 在实际场景中运行此测试时,您应该根据应用程序的隐私政策和相关的隐私法规确定哪些被认为是敏感数据。 一种推荐的方法是查看应用程序的隐私政策和 App Store 隐私声明。

mitm_sensitive_logger.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from mitmproxy import http

# This data would come from another file and should be defined after identifying the data that is considered sensitive for this application.
# For example by using the Google Play Store Data Safety section.
SENSITIVE_DATA = {
    "precise_location_latitude": "37.7749",
    "precise_location_longitude": "-122.4194",
    "name": "John Doe",
    "email_address": "[email protected]",
    "phone_number": "+11234567890",
    "credit_card_number": "1234 5678 9012 3456"
}

SENSITIVE_STRINGS = SENSITIVE_DATA.values()

def contains_sensitive_data(string):
    return any(sensitive in string for sensitive in SENSITIVE_STRINGS)

def process_flow(flow):
    url = flow.request.pretty_url
    request_headers = flow.request.headers
    request_body = flow.request.text
    response_headers = flow.response.headers if flow.response else "No response"
    response_body = flow.response.text if flow.response else "No response"

    if (contains_sensitive_data(url) or 
        contains_sensitive_data(request_body) or 
        contains_sensitive_data(response_body)):
        with open("sensitive_data.log", "a") as file:
            if flow.response:
                file.write(f"RESPONSE URL: {url}\n")
                file.write(f"Response Headers: {response_headers}\n")
                file.write(f"Response Body: {response_body}\n\n")
            else:
                file.write(f"REQUEST URL: {url}\n")
                file.write(f"Request Headers: {request_headers}\n")
                file.write(f"Request Body: {request_body}\n\n")
def request(flow: http.HTTPFlow):
    process_flow(flow)

def response(flow: http.HTTPFlow):
    process_flow(flow)
run.sh
1
mitmdump -s mitm_sensitive_logger.py

从 Android Studio 启动应用程序,然后单击该按钮,该按钮将通过网络发送敏感数据。 该脚本将捕获网络流量并记录敏感数据。

观察

该脚本已识别出网络流量中的多个敏感数据实例。

  • 第一个实例是向 https://httpbin.org/post 发送的 POST 请求,该请求在请求正文中包含敏感数据值。
  • 第二个实例是来自 https://httpbin.org/post 的响应,该响应在响应正文中包含敏感数据值。
sensitive_data.log
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
REQUEST URL: https://httpbin.org/post
Request Headers: Headers[(b'Content-Type', b'application/x-www-form-urlencoded'), (b'User-Agent', b'Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)'), (b'Host', b'httpbin.org'), (b'Connection', b'Keep-Alive'), (b'Accept-Encoding', b'gzip'), (b'Content-Length', b'188')]
Request Body: precise_location_latitude=37.7749&precise_location_longitude=-122.4194&name=John+Doe&email_address=john.doe%40example.com&phone_number=%2B11234567890&credit_card_number=1234+5678+9012+3456

RESPONSE URL: https://httpbin.org/post
Response Headers: Headers[(b'Date', b'Fri, 19 Jan 2024 10:17:44 GMT'), (b'Content-Type', b'application/json'), (b'Content-Length', b'735'), (b'Connection', b'keep-alive'), (b'Server', b'gunicorn/19.9.0'), (b'Access-Control-Allow-Origin', b'*'), (b'Access-Control-Allow-Credentials', b'true')]
Response Body: {
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "credit_card_number": "1234 5678 9012 3456", 
    "email_address": "[email protected]", 
    "name": "John Doe", 
    "phone_number": "+11234567890", 
    "precise_location_latitude": "37.7749", 
    "precise_location_longitude": "-122.4194"
  }, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "188", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 13; sdk_gphone64_arm64 Build/TE1A.220922.021)", 
    "X-Amzn-Trace-Id": "Root=1-65aa4c48-45514c0e3782665063b14397"
  }, 
  "json": null, 
  "origin": "148.141.65.87", 
  "url": "https://httpbin.org/post"
}

评估

在查看捕获的网络流量后,我们可以得出结论,测试失败,因为敏感数据通过网络发送。

这是一个虚拟示例,但在实际场景中,您应该确定哪些报告的实例与隐私相关,并且需要解决。

请注意,请求和响应都使用 TLS 加密,因此可以认为是安全的。 但是,根据相关的隐私法规和应用程序的隐私政策,这可能代表一个隐私问题。 您现在应该查看隐私政策和 App Store 隐私声明,以查看是否允许应用程序将此数据发送给第三方。