def test_duplicate_boundary_names_have_different_unique_names(self): object_1 = Boundary("foo") object_2 = Boundary("foo") object_1_uniq_name = _uniq_name(object_1.name, object_1.uuid) object_2_uniq_name = _uniq_name(object_2.name, object_2.uuid) self.assertNotEqual(object_1_uniq_name, object_2_uniq_name)
def test_defaults(self): tm = TM("my test tm", description="aa", isOrdered=True) internet = Boundary("Internet") cloud = Boundary("Cloud") user = Actor("User", inBoundary=internet) server = Server("Server") db = Datastore("DB", inBoundary=cloud) db.type = DatastoreType.SQL func = Datastore("Lambda function", inBoundary=cloud) request = Dataflow(user, server, "request") response = Dataflow(server, user, "response", isResponse=True) user_query = Dataflow(user, db, "user query") server_query = Dataflow(server, db, "server query") func_query = Dataflow(func, db, "func query") default_target = ["Actor", "Boundary", "Dataflow", "Datastore", "Server"] testCases = [ {"target": server, "condition": "target.oneOf(Server, Datastore)"}, {"target": server, "condition": "not target.oneOf(Actor, Dataflow)"}, {"target": request, "condition": "target.crosses(Boundary)"}, {"target": user_query, "condition": "target.crosses(Boundary)"}, {"target": server_query, "condition": "target.crosses(Boundary)"}, {"target": func_query, "condition": "not target.crosses(Boundary)"}, {"target": func_query, "condition": "not target.enters(Boundary)"}, {"target": func_query, "condition": "not target.exits(Boundary)"}, {"target": request, "condition": "not target.enters(Boundary)"}, {"target": request, "condition": "target.exits(Boundary)"}, {"target": response, "condition": "target.enters(Boundary)"}, {"target": response, "condition": "not target.exits(Boundary)"}, {"target": user, "condition": "target.inside(Boundary)"}, {"target": func, "condition": "not any(target.inputs)"}, { "target": server, "condition": "any(f.sink.oneOf(Datastore) and f.sink.type == DatastoreType.SQL " "for f in target.outputs)", }, ] self.assertTrue(tm.check()) for case in testCases: t = Threat(SID="", target=default_target, condition=case["condition"]) self.assertTrue( t.apply(case["target"]), "Failed to match {} against {}".format( case["target"], case["condition"], ), )
def makeBoundary(boundary_json): boundary_dict = copy.deepcopy(boundary_json) boundary = Boundary(boundary_dict.pop('name')) for k, v in boundary_dict.items(): if k == 'description': boundary.description = v elif k == 'inBoundary': # should only do this when we have all the boundary objects in a dict. otherwise # this will have an error. continue elif k == 'Options': for option, v_ in v.items(): replaceAttribute(boundary, option, v_) return boundary
def test_duplicate_boundary_names_have_different_unique_names(self): random.seed(0) object_1 = Boundary("foo") object_2 = Boundary("foo") object_1_uniq_name = object_1._uniq_name() object_2_uniq_name = object_2._uniq_name() self.assertNotEqual(object_1_uniq_name, object_2_uniq_name) self.assertEqual(object_1_uniq_name, "boundary_foo_acf3059e70") self.assertEqual(object_2_uniq_name, "boundary_foo_88f2d9c06f")
#!/usr/bin/env python3 from pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, Lambda tm = TM("my test tm") tm.description = "another test tm" Web = Boundary("Internal Web") external_web = Boundary("External Web") user = Actor("App-y-Tenant") app = Server("Mobile App") buy_api = Server("Buy<br/>API-y") buy_api.inBoundary = Web rent_api = Server("Rent<br/>API-y") rent_api.inBoundary = Web alert_api = Server("Alert<br/>API-y") alert_api.inBoundary = Web cloud = Server("Phone Provider Cloud") cloud.inBoundary = external_web alert_api_to_cloud = Dataflow(alert_api, cloud, "push") cloud_to_app = Dataflow(cloud, app, " ") db_b = Datastore("Oracle Table B") db_b.inBoundary = Web buy_api_to_db = Dataflow(buy_api, db_b, " ")
#!/usr/bin/env python3 import random from pytm.pytm import TM, Actor, Boundary, Dataflow, Datastore, Lambda, Server # make sure generated diagrams do not change, makes sense if they're commited random.seed(0) tm = TM("my test tm") tm.description = "This is a sample threat model of a very simple system - a web-based comment system. The user enters comments and these are added to a database and displayed back to the user. The thought is that it is, though simple, a complete enough example to express meaningful threats." tm.isOrdered = True tm.mergeResponses = True internet = Boundary("Internet") server_db = Boundary("Server/DB") vpc = Boundary("AWS VPC") user = Actor("User") user.inBoundary = internet web = Server("Web Server") web.OS = "Ubuntu" web.isHardened = True web.sanitizesInput = False web.encodesOutput = True web.authorizesSource = False db = Datastore("SQL Database") db.OS = "CentOS"
# Data Storages identity_db = Datastore("Identity - Mongo Atlas DB") token_blacklist_db = Datastore("Token Blacklist DB - Mongo Atlas DB") resources_db = Datastore("Resources - Mongo Atlas DB") s3_bucket = Datastore("AWS S3 Bucket - Persistent") # Monitoring kibana = Process("Kibana Visualising Dashboard") elastic_search_monitoring = Process("Elasticsearch Monitoring") logstash = Process("Logstash") heartbeat = Process("Heartbeat") apm_server = Process("Apm Server") # Boundraries hosted_services = Boundary("LetterApp DMZ") mongo_atlas = Boundary("Mongo Atlas Cluster") aws = Boundary("AWS VPC") external_services = Boundary("External Services") internet = Boundary("Internet") frontend = Boundary("Frontend") backend = Boundary("Backend") monitoring_vpc = Boundary("Monitoring VPC") monitoring_vpc.inBoundary = hosted_services # Add elements to boundraries monitong_elements = [ kibana, elastic_search_monitoring, logstash, heartbeat, apm_server ] for element in monitong_elements: element.inBoundary = monitoring_vpc
def test_defaults(self): internet = Boundary("Internet") cloud = Boundary("Cloud") user = Actor("User", inBoundary=internet) server = Server("Server") db = Datastore("DB", inBoundary=cloud) func = Datastore("Lambda function", inBoundary=cloud) request = Dataflow(user, server, "request") response = Dataflow(server, user, "response") user_query = Dataflow(user, db, "user query") server_query = Dataflow(server, db, "server query") func_query = Dataflow(func, db, "func query") default = { "SID": "", "description": "", "condition": "", "target": ["Actor", "Boundary", "Dataflow", "Datastore", "Server"], "details": "", "severity": "", "mitigations": "", "example": "", "references": "", } testCases = [ { "target": server, "condition": "target.oneOf(Server, Datastore)" }, { "target": server, "condition": "not target.oneOf(Actor, Dataflow)" }, { "target": request, "condition": "target.crosses(Boundary)" }, { "target": user_query, "condition": "target.crosses(Boundary)" }, { "target": server_query, "condition": "target.crosses(Boundary)" }, { "target": func_query, "condition": "not target.crosses(Boundary)" }, { "target": func_query, "condition": "not target.enters(Boundary)" }, { "target": func_query, "condition": "not target.exits(Boundary)" }, { "target": request, "condition": "not target.enters(Boundary)" }, { "target": request, "condition": "target.exits(Boundary)" }, { "target": response, "condition": "target.enters(Boundary)" }, { "target": response, "condition": "not target.exits(Boundary)" }, { "target": user, "condition": "target.inside(Boundary)" }, ] for case in testCases: t = Threat({**default, **{"condition": case["condition"]}}) self.assertTrue( t.apply(case["target"]), "Failed to match {} against {}".format(case["target"], case["condition"]), )
from pytm.pytm import TM, Boundary, Server, Actor, Datastore, Dataflow, SetOfProcesses tm = TM("App-y-ness") tm.description = "This is a sample threat model for the Threat Modeling Workshop." internet = Boundary("Internet") user = Actor("App-y-tenant") app = Server("Mobile App") buyApi = Server("Buy<br/>API-y") buyApi.inBoundary = internet rentApi = Server("Rent<br/>API-y") rentApi.inBoundary = internet market = SetOfProcesses("Market-y") market.inBoundary = internet alertApi = Server("Alert<br/>API-y") alertApi.inBoundary = internet authApi = Server("Auth<br/>API-y") authApi.inBoundary = internet allAuth = Server("All Auth") allAuth.inBoundary = internet phoneCloud = Server("Phone<br/>Provider<br/>Cloud")
# !/usr/bin/env python3 from pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, Lambda, Process tm = TM("Kubernetes Threat Model") tm.description = "a deep-dive threat model of Kubernetes" # Boundaries inet = Boundary("Internet") mcdata = Boundary("Master Control Data") apisrv = Boundary("API Server") mcomps = Boundary("Master Control Components") worker = Boundary("Worker") contain = Boundary("Container") # Actors miu = Actor("Malicious Internal User") ia = Actor("Internal Attacker") ea = Actor("External Actor") admin = Actor("Administrator") dev = Actor("Developer") eu = Actor("End User") # Server & OS Components etcd = Datastore("N-ary etcd servers") apiserver = Server("kube-apiserver") kubelet = Server("kubelet") kubeproxy = Server("kube-proxy")
#!/usr/bin/env python3 from pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor tm = TM("my test tm") tm.description = "This is a sample threat model of a very simple system - a web-based comment system. The user enters comments and these are added to a database and displayed back to the user. The thought is that it is, though simple, a complete enough example to express meaningful threats." User_Web = Boundary("User/Web") Web_DB = Boundary("Web/DB") user = Actor("User") user.inBoundary = User_Web web = Server("Web Server") web.OS = "CloudOS" web.isHardened = True db = Datastore("SQL Database (*)") db.OS = "CentOS" db.isHardened = False db.inBoundary = Web_DB db.isSql = True db.inScope = False user_to_web = Dataflow(user, web, "User enters comments (*)") user_to_web.protocol = "HTTP" user_to_web.dstPort = 80 user_to_web.data = 'Comments in HTML or Markdown' user_to_web.order = 1 user_to_web.note = "This is a note\nmulti-line"
# !/usr/bin/env python3 from pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, ExternalEntity, Process tm = TM("Basic threat model") tm.description = "DFD for storytelling exercise" # Define boundaries User = Boundary("User") API = Boundary("Internet facing") DB = Boundary("Database") test = ExternalEntity("test") test.implementsNonce = False # Define actors user = Actor("User") user.inBoundary = User # Define components api_search = Server("api_search") api_search.inBoundary = API api_search.inScope = True api_search.providesConfidentiality = True api_reservation = Server("api_reservation") api_reservation.inBoundary = API api_reservation.inScope = True api_rating = Server("api_rating") api_rating.inBoundary = API
def test_defaults(self): internet = Boundary("Internet") cloud = Boundary("Cloud") user = Actor("User", inBoundary=internet) server = Server("Server") db = Datastore("DB", inBoundary=cloud) func = Datastore("Lambda function", inBoundary=cloud) request = Dataflow(user, server, "request") response = Dataflow(server, user, "response") user_query = Dataflow(user, db, "user query") server_query = Dataflow(server, db, "server query") func_query = Dataflow(func, db, "func query") default_target = [ "Actor", "Boundary", "Dataflow", "Datastore", "Server" ] testCases = [ { "target": server, "condition": "target.oneOf(Server, Datastore)" }, { "target": server, "condition": "not target.oneOf(Actor, Dataflow)" }, { "target": request, "condition": "target.crosses(Boundary)" }, { "target": user_query, "condition": "target.crosses(Boundary)" }, { "target": server_query, "condition": "target.crosses(Boundary)" }, { "target": func_query, "condition": "not target.crosses(Boundary)" }, { "target": func_query, "condition": "not target.enters(Boundary)" }, { "target": func_query, "condition": "not target.exits(Boundary)" }, { "target": request, "condition": "not target.enters(Boundary)" }, { "target": request, "condition": "target.exits(Boundary)" }, { "target": response, "condition": "target.enters(Boundary)" }, { "target": response, "condition": "not target.exits(Boundary)" }, { "target": user, "condition": "target.inside(Boundary)" }, ] for case in testCases: t = Threat(SID="", target=default_target, condition=case["condition"]) self.assertTrue( t.apply(case["target"]), "Failed to match {} against {}".format(case["target"], case["condition"]), )