Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Melinda Shore - Advanced DNS Services for Securing Your Application and Enhancing User Privacy

Melinda Shore - Advanced DNS Services for Securing Your Application and Enhancing User Privacy

This talk introduces new features that have been added to the Domain Name System recently, and how to use those features to improve application security and user privacy. I also introduce the "getdns" Python library, which provides a simplified DNS API, and how to interface with popular crypto libraries.

https://us.pycon.org/2016/schedule/presentation/2004/

PyCon 2016

May 29, 2016
Tweet

More Decks by PyCon 2016

Other Decks in Programming

Transcript

  1. GETDNS • new DNS library • one-step DNSSEC validation •

    transport options to protect user privacy, avoid middlebox woes
  2. GETDNS • Original specification was for a C API, actually

    fits Python and other modern languages somewhat better (data structures) • Language bindings: Python, node.js, PHP. Ruby is under development. • Hackathons: TNW, IETF. Won “Best Internet Security Improvement” at IETF 94 hackathon in November
  3. 5-MINUTE DNS TUTORIAL • stateless query-response protocol • send a

    query to your DNS server, it returns your query along with a set of answers • DNS resource records
  4. DNS STRUCTURE . .org .com .uk .biz .reisen ietf eff

    python isoc mail pypi www root zone TLDs second-level domains
  5. DIG EXAMPLE Melindas-MacBook-Pro:~ melinda$ which dig /usr/bin/dig Melindas-MacBook-Pro:~ melinda$ dig

    getdnsapi.net a ! ; <<>> DiG 9.8.3-P1 <<>> getdnsapi.net a ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1925 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ! ;; QUESTION SECTION: ;getdnsapi.net. IN A ! ;; ANSWER SECTION: getdnsapi.net. 449 IN A 185.49.141.37 ! ;; Query time: 244 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Thu May 26 20:06:01 2016 ;; MSG SIZE rcvd: 47 ! Melindas-MacBook-Pro:~ melinda$
  6. DNSSEC • The problem: it’s easy to forge DNS packets,

    with obvious consequences (AKA “Kaminsky attack,” after Dan Kaminsky) • DNSSEC is a mechanism to prove the authenticity of a DNS record • The trust model: hierarchy of signed records chaining up to the DNS root zone
  7. DNSSEC EXAMPLE Melindas-MacBook-Pro:src melinda$ dig +dnssec getdnsapi.net a ! ;

    <<>> DiG 9.8.3-P1 <<>> +dnssec getdnsapi.net a ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27162 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ! ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 512 ;; QUESTION SECTION: ;getdnsapi.net. IN A ! ;; ANSWER SECTION: getdnsapi.net. 417 IN A 185.49.141.37 getdnsapi.net. 417 IN RRSIG A 7 2 450 20160608170833 20160518143030 23885 getdnsapi.net. bDcGGokWnupa9khd8rhr0SbjUEXHFmCpUWlbkNeXZx/Ugy90eWvpcY72 H2LWale/2CP5Q4V/+M0XMnEakkZOFBA3h58n/8pGK3MuSHthX/ E0CD1b DFvCgfeLxyFde5RoIpZ6Mx0SVG5/3A/Lc2Yn56MUcBecLKHBNLqv+oux /Ys= ! ;; Query time: 133 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Thu May 26 21:47:11 2016 ;; MSG SIZE rcvd: 231
  8. ENTER GETDNS shore@birch:~/src/tmp$ cat simple.py import getdns, sys ! context

    = getdns.Context() ext = { 'dnssec_return_only_secure': getdns.EXTENSION_TRUE } r = context.address(sys.argv[1], extensions=ext) if r.status == getdns.RESPSTATUS_GOOD: for addr in r.just_address_answers: print(addr['address_data']) if r.status == getdns.RESPSTATUS_NO_SECURE_ANSWERS: print("No secure answers”) ! shore@birch:~/src/tmp$ python simple.py getdnsapi.net 2a04:b900:0:100::37 185.49.141.37 ! shore@birch:~/src/tmp$ python simple.py google.com No secure answers shore@birch:~/src/tmp$
  9. A NEW TRUST MODEL FOR THE INTERNET Hey, this thing

    securely serves up public keys!
  10. PKI • You’ve got to trust somebody • the public

    key infrastructure is also based on a hierarchy of credentials chaining back to a root • browser vendors end up making decisions about what goes in the root trust store • That hasn’t always worked out well
  11. PKI ISSUES • certificate “misissuance” • careless key usage constraints

    — people posing as CAs and issuing certs • compromised CAs
  12. DANE • DNS-Based Authentication of Named Entities • Here’s the

    idea: move trust management and credential validation closer to an organization’s own infrastructure • Here’s the implementation: put public key credentials in the DNS, protected by DNSSEC
  13. DANE • to authenticate TLS servers, retrieve a TLSA record

    from the DNS • make sure its signature checks out • compare the certificate in the TLSA record with the one presented in the TLS server_hello
  14. RETRIEVE THE TLSA RECORD ctx = getdns.Context() try: results =

    ctx.general(name=qname, request_type=getdns.RRTYPE_TLSA, extensions=extensions)
  15. PULL DATA OUT OF THE RECORD def get_tlsa_rdata_set(replies, requested_usage=None): tlsa_rdata_set

    = [] for reply in replies: for rr in reply['answer']: if rr['type'] == getdns.RRTYPE_TLSA: rdata = rr['rdata'] usage = rdata['certificate_usage'] selector = rdata['selector'] matching_type = rdata['matching_type'] cadata = rdata['certificate_association_data'] cadata = str(cadata).encode('hex') if usage == requested_usage: tlsa_rdata_set.append( (usage, selector, matching_type, cadata) ) return tlsa_rdata_set
  16. COMPARE WHAT YOU’VE GOT def verify_tlsa(cert, usage, selector, matchtype, hexdata1):

    ! if selector == 0: certdata = cert.as_der() elif selector == 1: certdata = cert.get_pubkey().as_der() else: raise ValueError("selector type %d not recognized" % selector) ! if matchtype == 0: hexdata2 = hexdump(certdata) elif matchtype == 1: hexdata2 = compute_hash(hashlib.sha256, certdata) elif matchtype == 2: hexdata2 = compute_hash(hashlib.sha512, certdata) else: raise ValueError("matchtype %d not recognized" % matchtype) ! if hexdata1 == hexdata2: return True else: return False
  17. OTHER DANE APPLICATIONS • openpgp keys • S/MIME keys •

    use of TLSA records to protect SMTP sessions
  18. DNS PRIVACY • IETF RFC 7258: “Pervasive monitoring is a

    technical attack that should be mitigated in the design of IETF protocols, where possible.” • DNS leaks a massive amount of information about what a user is doing on the network
  19. PRIVACY PROTECTION • TLS transport: 
 context.dns_transport_list = [ getdns.TRANSPORT_TLS

    ] • Padding: 
 context.tls_query_padding_blocksize = 256
  20. “ROADBLOCK” AVOIDANCE • Middleboxes (firewalls, NATs, other stateful transport intermediaries)

    sometimes filter out DNS traffic it misidentifies as malicious • The underlying getdns library detects these and works around them
  21. STATUS • Now feature-complete with respect to the original spec

    • Ongoing integration of new protocol features • Python bindings have been very useful for quick prototyping
  22. FIND US! • Project home page: https://getdnsapi.net • Github: https://github.com/getdnsapi

    • PyPI: https://pypi.python.org/pypi/getdns/v1.0.0b1 • Documentation: http://getdns.readthedocs.org/ • Docker image: https://hub.docker.com/r/melindashore/ getdns-python2/
  23. UPCOMING HACKATHON • IETF 96 Hackathon, Berlin, Germany • Intercontinental

    Hotel, July 16/17, 2016 • You do not need to be registered for or participating in the IETF meeting • Potential projects include: a getdns protocol for Twisted, a DANE API, or your excellent idea • http://ietf.org/hackathon/96-hackathon.html