def test_responses(self): tm = TM("my test tm", description="aa", isOrdered=True) user = Actor("User") web = Server("Web Server") db = Datastore("SQL Database") http_req = Dataflow(user, web, "http req") insert = Dataflow(web, db, "insert data") query = Dataflow(web, db, "query") query_resp = Dataflow(db, web, "query results", responseTo=query) http_resp = Dataflow(web, user, "http resp") http_resp.responseTo = http_req self.assertTrue(tm.check()) self.assertEqual(http_req.response, http_resp) self.assertIs(http_resp.isResponse, True) self.assertIs(query_resp.isResponse, True) self.assertEqual(query_resp.responseTo, query) self.assertEqual(query.response, query_resp) self.assertIsNone(insert.response) self.assertIs(insert.isResponse, False)
def test_load_threats(self): tm = TM("TM") self.assertNotEqual(len(TM._threats), 0) with self.assertRaises(FileNotFoundError): tm.threatsFile = "threats.json" with self.assertRaises(FileNotFoundError): TM("TM", threatsFile="threats.json")
class ThreatModel: def __init__(self, name, description="My TM", isOrdered=True, mergeResponses=True): self.tm = TM(name) self.tm.description=description self.tm.isOrdered = isOrdered self.tm.mergeResponses = mergeResponses def start(self): self.tm.process()
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"], ), )
#!/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, " ")
def test_defaults(self): tm = TM("TM") user = Actor("User", data="HTTP", authenticatesDestination=True) server = Server("Server", port=443, protocol="HTTPS", isEncrypted=True, data="JSON") db = Datastore( "PostgreSQL", isSQL=True, port=5432, protocol="PostgreSQL", isEncrypted=False, data="SQL resp", ) worker = Process("Task queue worker") req_get = Dataflow(user, server, "HTTP GET") server_query = Dataflow(server, db, "Query", data="SQL") result = Dataflow(db, server, "Results", isResponse=True) resp_get = Dataflow(server, user, "HTTP Response", isResponse=True) req_post = Dataflow(user, server, "HTTP POST", data="JSON") resp_post = Dataflow(server, user, "HTTP Response", isResponse=True) worker_query = Dataflow(worker, db, "Query", data="SQL") Dataflow(db, worker, "Results", isResponse=True) cookie = Data("Auth Cookie", carriedBy=[req_get, req_post]) self.assertTrue(tm.check()) self.assertEqual(req_get.srcPort, -1) self.assertEqual(req_get.dstPort, server.port) self.assertEqual(req_get.isEncrypted, server.isEncrypted) self.assertEqual(req_get.authenticatesDestination, user.authenticatesDestination) self.assertEqual(req_get.protocol, server.protocol) self.assertTrue(user.data.issubset(req_get.data)) self.assertEqual(server_query.srcPort, -1) self.assertEqual(server_query.dstPort, db.port) self.assertEqual(server_query.isEncrypted, db.isEncrypted) self.assertEqual(server_query.authenticatesDestination, server.authenticatesDestination) self.assertEqual(server_query.protocol, db.protocol) self.assertTrue(server.data.issubset(server_query.data)) self.assertEqual(result.srcPort, db.port) self.assertEqual(result.dstPort, -1) self.assertEqual(result.isEncrypted, db.isEncrypted) self.assertEqual(result.authenticatesDestination, False) self.assertEqual(result.protocol, db.protocol) self.assertTrue(db.data.issubset(result.data)) self.assertEqual(resp_get.srcPort, server.port) self.assertEqual(resp_get.dstPort, -1) self.assertEqual(resp_get.isEncrypted, server.isEncrypted) self.assertEqual(resp_get.authenticatesDestination, False) self.assertEqual(resp_get.protocol, server.protocol) self.assertTrue(server.data.issubset(resp_get.data)) self.assertEqual(req_post.srcPort, -1) self.assertEqual(req_post.dstPort, server.port) self.assertEqual(req_post.isEncrypted, server.isEncrypted) self.assertEqual(req_post.authenticatesDestination, user.authenticatesDestination) self.assertEqual(req_post.protocol, server.protocol) self.assertTrue(user.data.issubset(req_post.data)) self.assertEqual(resp_post.srcPort, server.port) self.assertEqual(resp_post.dstPort, -1) self.assertEqual(resp_post.isEncrypted, server.isEncrypted) self.assertEqual(resp_post.authenticatesDestination, False) self.assertEqual(resp_post.protocol, server.protocol) self.assertTrue(server.data.issubset(resp_post.data)) self.assertListEqual(server.inputs, [req_get, req_post]) self.assertListEqual(server.outputs, [server_query]) self.assertListEqual(worker.inputs, []) self.assertListEqual(worker.outputs, [worker_query]) self.assertListEqual(cookie.carriedBy, [req_get, req_post]) self.assertSetEqual(set(cookie.processedBy), set([user, server])) self.assertIn(cookie, req_get.data) self.assertSetEqual(set([d.name for d in req_post.data]), set([cookie.name, "HTTP", "JSON"]))
def __init__(self, name, description="My TM", isOrdered=True, mergeResponses=True): self.tm = TM(name) self.tm.description=description self.tm.isOrdered = isOrdered self.tm.mergeResponses = mergeResponses
#!/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"
def test_defaults(self): tm = TM("TM") user = Actor("User", data="HTTP") server = Server("Server", port=443, protocol="HTTPS", isEncrypted=True, data="JSON") db = Datastore( "PostgreSQL", isSQL=True, port=5432, protocol="PostgreSQL", isEncrypted=False, data="SQL resp", ) req_get = Dataflow(user, server, "HTTP GET") query = Dataflow(server, db, "Query", data="SQL") result = Dataflow(db, server, "Results", isResponse=True) resp_get = Dataflow(server, user, "HTTP Response", isResponse=True) req_post = Dataflow(user, server, "HTTP POST", data="JSON") resp_post = Dataflow(server, user, "HTTP Response", isResponse=True) tm.check() self.assertEqual(req_get.srcPort, -1) self.assertEqual(req_get.dstPort, server.port) self.assertEqual(req_get.isEncrypted, server.isEncrypted) self.assertEqual(req_get.protocol, server.protocol) self.assertEqual(req_get.data, user.data) self.assertEqual(query.srcPort, -1) self.assertEqual(query.dstPort, db.port) self.assertEqual(query.isEncrypted, db.isEncrypted) self.assertEqual(query.protocol, db.protocol) self.assertNotEqual(query.data, server.data) self.assertEqual(result.srcPort, db.port) self.assertEqual(result.dstPort, -1) self.assertEqual(result.isEncrypted, db.isEncrypted) self.assertEqual(result.protocol, db.protocol) self.assertEqual(result.data, db.data) self.assertEqual(resp_get.srcPort, server.port) self.assertEqual(resp_get.dstPort, -1) self.assertEqual(resp_get.isEncrypted, server.isEncrypted) self.assertEqual(resp_get.protocol, server.protocol) self.assertEqual(resp_get.data, server.data) self.assertEqual(req_post.srcPort, -1) self.assertEqual(req_post.dstPort, server.port) self.assertEqual(req_post.isEncrypted, server.isEncrypted) self.assertEqual(req_post.protocol, server.protocol) self.assertNotEqual(req_post.data, user.data) self.assertEqual(resp_post.srcPort, server.port) self.assertEqual(resp_post.dstPort, -1) self.assertEqual(resp_post.isEncrypted, server.isEncrypted) self.assertEqual(resp_post.protocol, server.protocol) self.assertEqual(resp_post.data, server.data)
#!/usr/bin/env python3 # TM, Element, Server, ExternalEntity, Datastore, Actor, Process, SetOfProcesses, Dataflow, Boundary and Lambda. from pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, Lambda, Element, Process, ExternalEntity, Classification tm = TM("LetterApp flow diagram") tm.description = """LetterApp is a cloud-based and machine learning-powered document-management and workflow system which allow users to upload documents and access them from a Web client and a mobile client, as well as programtically through a group of Restful API's. Besides making the documents avaiable across devices, it also allows for flow management - users can group, tag, and track activities related to each document. Computer vision helps users with automatic tagging and entity extraction. Users can also send letters, faxes na messages straight from the app. Since the nature of the data stored is sensitve, security is of heightened importance for the app's development.""" tm.isOrdered = True tm.mergeResponses = True tm #Actors #TODO add mobile client? programtic user? anonymous user? #External Entities - out of control #Sendgrid #External Entities / Processes / Actors web_user = ExternalEntity('Web User') administrator = ExternalEntity('Administrator') mobile_client = ExternalEntity("Mobile Client") direct_api = ExternalEntity("API programatic access")
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, 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
from pytm.pytm import TM, Boundary, Server, Actor, Datastore, Dataflow, SetOfProcesses tm = TM("Generic CMS example") tm.description = "This is a sample threat model for the Threat Model Cookbook." internet = Boundary("Internet") user = Actor("Generic/Privilege User") webserver = Server("Web Server") webserver.inBoundary = internet user_to_webserver = Dataflow(user, webserver, "HTTPS") db = Datastore("db") db.inBoundary = internet db_to_webserver = Dataflow(webserver, db, " ") adminuser = Actor(" admin ") admin_to_webserver = Dataflow(adminuser, db, "unsecure<br/>mysql<br/>connection") cdn = SetOfProcesses("CDN network") user_to_cdn = Dataflow(user, cdn, "HTTP") webserver_to_cdn = Dataflow(webserver, cdn, "Push to Bucket") tm.process()