Do you write Python software that uses a network, opens files, or even accepts user input?
Of course you do. That's what almost all software does. But these actions can let bad actors exploit
mistakes and oversights we've made in our code that will allow them to compromise our systems.
Python is safer than some languages, but there are plenty of issues to be careful of.
That's why Anthony Shaw and Anthony Lingsworth are here to discuss Python security. This is
Talk Python to Me, episode 168, recorded June 28th, 2018.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem,
and the personalities. This is your host, Michael Kennedy. Follow me on Twitter, where I'm at
M. Kennedy. Keep up with the show and listen to past episodes at talkpython.fm, and follow the
show on Twitter via at Talk Python. Anthony Shaw, Anthony Lingsworth, welcome to Talk Python.
Hey, Michael. It's great to be back.
Hey, Michael. Good to be my first time.
Yeah, it's good to have you here. So we have a bit of a name conflict here. So Anthony Shaw's
aunt, and Anthony Lingsworth is Anthony for the rest of the show. Hopefully that works for you all out
there listening. And we're going to cover something that I think is often overlooked in Python,
the whole security side of things, right? I mean, I feel like, well, there's no buffer overflow issues and
things like that. So we must be just totally fine, right?
No. If only that was the case. If only that was the case.
Exactly. There's actually a ton of interesting vulnerabilities and things that are pretty common,
I suspect, still in some circumstances that we're going to go through. But before we do,
I'd like to hear your guys' story really quick. Anthony, how'd you get into programming in Python?
I mainly got into programming Python through networking programming. One of my responsibilities
here is interacting with a lot of Cisco and Juniper and other hardware, and Python is what they use.
Right on. And Ant, you talked about getting started on Lib Cloud last time, right?
Yeah, that was me. I was in Seattle and I got sick, and I was stuck in a hotel for the weekend,
so I learned Python. I never looked back since then.
Most people say, I got really sick, so I stayed in bed. Other people like you are like,
oh, I learned a new programming language because I wasn't feeling well.
I had nowhere to go.
That's awesome. I totally get it. Let's start first talking about just security in general.
Anthony, how do you think we should start thinking about security as software developers
and people that run servers and stuff like that?
What I tell people is when they start thinking about security, they have to invert how they think.
Developers are very good at thinking, how do I build something quickly and that's designed well
and that keeps my customers happy? Security is not like that. Security is how do I break something?
How do I compromise something? How do I bend the rules?
So you almost need a tester style thinking.
So you look at what you've built and think, well, how do I make it do things it's not meant to do?
I find there's just so much creativity in that.
It's really hard to think about.
And unless you see some examples of it in action, it's almost hard to conceptualize some of these things.
Like I remember the first time I saw the actual code for a buffer overflow exploit.
Here's how you overflow the buffer.
Here's how you get it to execute those bits that you've dropped in.
I'm just like, that is just, that's a different way of thinking, let's say.
Yeah. I mean, as you say, some of the people who do this, they're really smart and they get really technical.
But I also want to stress that a lot of this stuff is not rocket science.
A lot of this is looking at what you do and just trying to keep that mindset.
Yeah, I think that's a really good point.
It's easy to get overwhelmed thinking, you know, this stuff is super advanced.
But actually, 99% of the time, it's like, did you change the password from the default admin password on the database and stuff like that, right?
That's where people usually start whacking on it, right?
Exactly. Exactly.
I mean, most people make a big deal about the super, super complex hacks out there.
But if you talk to people like Kevin Mitnick and so on, a lot of the stuff they were doing is social engineering, which is just simple, as you say, password stuff or basic configurations.
A lot of the times with security, if you get the basics right, the simple stuff right, the attackers will just go elsewhere because they're looking for the easiest exploit.
Yeah, they're just rattling the door to see if it's open, right?
Exactly.
Yeah. And how about you? What are your thoughts on the sort of security thinking versus developer thinking?
Yeah, I mean, I guess that probably the difference between Anthony and I, which is, I guess, confusing because we have the same name.
Although we sound quite different, hopefully that'll be more obvious to the viewer if we have different accents.
Is that Anthony spends a lot of his time, I guess, looking at things from the security angle, whereas most of my time has been spent from a development angle.
And I've been curious about security, I guess, for a long time.
My first job was doing sort of system support for servers and dealing with hacked servers was a pretty common occurrence.
And I guess learning how people got into the systems, what they did once they got there.
And it was kind of shown in the movies, like there's, you know, this person in a dark room with like a green screen and it's all like super technical.
And they've always got a hoodie on and they're always playing some sort of like metal music in the background.
But actually, when you're more familiar with, I guess, how systems get compromised, it's just people running scripts that just pinging server after server after server looking for known vulnerabilities.
And if people haven't configured stuff properly or they've left bad usernames, bad passwords, then they just poke a hole in it and then have their fun, basically.
I mean, that takes up a lot of people's time and a lot of the security challenges.
So my kind of curiosity has been, how can I write code in a way that I'm not doing things which the attackers are going to be excited about?
Like, what mistakes could I be making in my code that they're going to be like, ah, fool, he left this particular vulnerability.
He didn't read this obscure documentation page.
And it does come across like that to people.
Like, it seems hard, which is, I guess, why I put the article together to point out some of the more obvious ones.
And they're not that complicated.
Yeah, that's a really good point.
Most of it isn't that complicated.
It's just knowing that what is out there.
You know, me personally, I don't think about it the way that you do, Anthony, in terms of like, how can I break things?
I think of it more as like a super paranoid, forgetful person, which I'm fairly forgetful in general life as it is, but not paranoid.
But I'm always thinking like, oh my gosh, what have I forgotten?
What is the thing that is just wide open that I forgot?
Did I forget to turn on the firewall that blocks the database port publicly?
Did I forget to, you know, validate this one thing?
I think, you know, a while ago there was one admin page on my site that didn't check whether this person was an admin or not.
And if you could come up with this random URL, you could have found it.
I'm like, oh my gosh, I can't believe I forgot that.
So that's sort of my feeling is like a constant uneasiness.
I know there's thousands of people attacking this site constantly, but throughout, you know, they sort of continuously, I guess.
And it's like, well, when will they find the thing I forgot?
It's an ego driven security as it's called.
But that's cool.
That's cool.
If it makes you more secure, then go for it, please.
Yeah, I think it probably does.
I mean, I'm always double checking stuff and I think it does really, really help.
So there's a lot of these things you can address.
And I think it's probably time to go through this list.
So when Brian and I spoke about this on Python Bytes just yesterday, actually it came out today, but we recorded it yesterday.
And he was like, well, the ones that were obvious, they're not even here.
I mean, some of them are, but some of them are like Python, you know, there's the eval, eval user input.
Like, don't do that, right?
So I think you have a really interesting list that you put together here.
Some of which will be people like, oh yeah, I've heard of that.
Others like, really?
I didn't know that was a problem.
And then they'll frantically pause the podcast and they'll run away and go look at their systems.
So you want to take us through the topics and we can sort of spend a little time on each one?
Yeah, sure.
So I guess I left out some really obvious ones.
I mean, eval is probably the worst one.
Like you wouldn't just accept input from the internet and pass it through eval, I'd hope.
You say that.
I'm sure it's happening all over the place.
It's easier to sort that way when you just pass the lambda on the command line.
Yeah, the PHP equivalent is the reason that you're getting all those entries in your logs looking for wp-admin.
Anyway, so I guess the number one is
input injection, which is just common across languages, across frameworks.
It's nothing specific to Python.
It's basically noticing that you're creating SQL queries and you're taking a parameter and you're injecting it into a string literal.
And what they can do is they can escape the quotes you put around the argument or the filter or whatever it was.
And they can basically run arbitrary SQL queries on your table.
So SQL injection, I think, is pretty well known.
It's pretty easy to avoid.
There are libraries for doing sensible escaping.
There are libraries for basically parameterizing your SQL queries, which is really the way it should be done.
But time and time again, that's probably seen as one of the most common things in web applications.
And it's just one of those things that won't die, right?
Like it's just there's still popular blog posts that have examples of SQL injection attacks all over.
And people just read until they get it to work.
They don't go to the comments and say, don't do this.
Don't do this.
Yeah, because it's like when you learn SQL or if you learn how to create SQL queries, it doesn't like there are so many tutorials out there that actually show you the wrong way to do it.
So this is why it keeps happening.
Yeah, this is why it keeps happening because people are like, this is how you write a SQL query.
And then, OK, you want to filter by a particular user or a particular ID or whatever.
Here's how you write a where clause.
And, oh, let's take that as a parameter.
Yeah, yeah, because it's simpler, right?
People are learning the wrong way to do it every day.
And we're having to unteach them that kind of practice.
Luckily, there's a cartoon to remind us.
SKCD.
Yeah.
Are you familiar with little Bobby tables?
Yeah, absolutely.
And I've seen the picture.
There's a photograph as well as of a car where someone's put on their license plate.
They've actually tried to put SQL injection on their license plate.
Get all those license plate readers.
That was brilliant.
Yeah.
So the license plate readers would crash.
That's the intention anyway.
And then I guess the other version of that is command injection,
where you have a script which needs to call a local process on the machine,
like an encoder or a specific executable or something like that.
I mean, Python has a few ways of doing that in the standard library.
There's subprocess.
There's popen.
There's in the OS module.
There's another way.
And there's many ways that similar to SQL injection, you can take an argument from somewhere and people can escape that argument and use it to run arbitrary commands on the server.
So that's command injection or shell injection is called.
That sounds a little bit bad.
And that one actually was surprising to me.
I wasn't super familiar with that.
But if you're going to do popen and pass a string as the command to run, you could easily do dollar sign, dollar sign, next command or semicolon or whatever the separator your shell uses.
Because you can issue commands that have multiple operations one after another in a single line, right?
Yeah, so the most common example is somebody writing a, basically calling an executable and then giving it an argument.
Let's say you want to create a thumbnail or encode an MP4 or something.
Then you'd call a local process which does the encoding and you'd give it an argument which is the name of the file you want to encode.
So that's straightforward, except that if instead of a file name, they close the quote and then they do a semicolon or an amphosand, amphosand, and then they can put in any other command they like.
How could that be wrong?
How could it go wrong?
And it's funny because I shared this post and I saw some of the discussion forums, people arguing back saying, oh no, that's not a problem.
Why, how could that possibly be a vulnerability?
And even if you kind of like make it really obvious, people don't look at it like an attacker would look at it.
They look at it like, oh, who would misuse that?
How could that happen?
Exactly.
That's flexibility.
It's good.
It means good things.
Yeah, and I think it's really interesting to have these two contrasts, not just SQL injection.
And I was going to add too that there's, in addition to the escaping and stuff that Ant is talking about, there's additional things you can do here to protect yourself.
So, for example, if you can run as the least privileged account you can.
So, don't run as root or administrator, for example.
So, if you do happen to have a bug in your application where someone can do command injection, you're going to minimize what it can do.
So, there's multiple levels of ways you can protect yourself here as well.
I think that's a really good point for a lot of this stuff, right?
It's sort of security as layers, not the one big silver bullet, right?
Yes, very much so.
Yeah.
The Python way around that is, well, first of all, avoid doing this if possible.
I mean, there's many other ways of doing spawning processes and doing them correctly.
But if you have to, if you need to escape the input, then use the shlex module, which is built into the standard library, and it has a utility function for escaping shell commands.
Yeah.
What I really like about your article, which I don't know if we've said it explicitly, it's 10 common security gotchas in Python and how to avoid them.
And we'll put that in the show notes, of course.
And for many of these, you have these, oh, did you know there's this other module you can just use that fixes this problem?
So, that's, it's really nice that you have sort of some way to deal with this, not just like to put paranoia into people.
This episode of Talk Python to Me is brought to you by Test and Code and the Python Bytes podcasts.
If you love podcasts in Python, and you're listening to mine, so you must, right?
Well, don't miss out on these two other great podcasts.
If you're in a hurry and just want the headlines, get the rapid fire Python Bytes podcast that I co-host with Brian Okken over at pythonbytes.fm.
Brian also hosts his own show, Test and Code, at testandcode.com, where he explores topics like test-driven development, continuous integration, code coverage, and pytest, of course, as well as agile development, mentoring, public speaking, and lots more in an opinionated mix of interviews and solo episodes.
Keep up with the latest news and become a better developer by listening to Python Bytes and Test and Code.
The next group of attacks are all related to deserializing or serializing data.
And this is a pretty common vector where, let's say you're writing an application that reads configuration from somewhere.
And that could be in YAML or JSON or XML, or it's receiving a message from somewhere, or you're basically using it as a way of communicating between different processes.
There's different ways you can do that in Python.
You could use XML, you could use JSON, you could use YAML, or you could use pickle files.
So all four of those have massive gaping holes in them, which you could drive a bus through.
So I kind of explained how you could abuse each one of them.
I guess people might assume that XML is the safest.
Yeah, it seems sort of old school, but XML can get complicated on the edges, you know, like weird namespaces and referring back to itself and other sorts of bizarre things that nobody ever does.
Yeah.
So the one I kind of explained was the billion, what's called the billion laughs exploit.
It's funny.
And it's, you know, look, if you're going to get like taken down, at least it should be a funny sort of hack, right?
Come on.
Got to appreciate it.
So this is if you wanted to, if you received an XML payload from somewhere and an attacker has access to put their own XML in there, then basically XML has this thing called entity expansion.
I guess the most similar way to think of it is a zip file.
And what you could do, imagine you created a text file and it just contained spaces, lots and lots and lots of spaces, like let's say a million spaces.
Now, if you compress that into zip, it compresses down to nothing because the way compression algorithms work.
But when you extract it, it's like, oh, it's one character.
Yeah, exactly.
So it can condense down to pretty much nothing.
Let's say you compress that into a zip file and then you made 10 of those, you copied it and you pasted it 10 times.
And then you copied those 10 zip files and then added them to a zip file and then did that again and again and again.
Now, what happens is if you extracted that zip file, it will go and sort of recursively extract the zips.
And it can go from something like a one kilobyte zip file to gigabytes or potentially even worse.
So the XML version, that's called a zip bomb.
The XML version is a similar idea where in XML, you can have basically you can sort of reference things.
And so in entity expansion, it can kind of reference something which references something.
So it's similar to the zip bomb where you kind of create this tree and then it basically exponentially expands.
So when you're trying to deserialize this special message in XML, it can take up gigabytes of RAM.
So that is basically the exploit is that it just takes your server offline.
And here it is fitting on one screen with word wrapping.
Yeah.
And it's like eight lines of XML.
Yeah.
It sort of teaches you that exponential stuff and like factorial type things.
They get big fast.
Yeah, exactly.
So the XML one's pretty bad.
There's some other pretty well-known ones with XML.
So if you actually look at the standard library documentation for Python, and this is how I came across this.
It does say in a big red box that there are known security challenges with XML.
And you shouldn't deserialize arbitrary XML documents.
Unless you do like soap web services, then what could go wrong?
Exactly.
So I guess the alternative is you can use a package called defused XML, which is a third party package.
But it was actually written by Christian Himes, who's one of the core developers on Python.
He's a security expert at Red Hat.
So he kind of put together, I guess, a safer version of the XML standard library module.
And it's a drop-in replacement.
That's awesome.
Does it just like not support these self-referential things and some of the other dangerous bits?
It's like a limited XML?
Stuff that it would be really unlikely you'd have to use anyway.
Yeah.
Anthony, as a network person, how do you think about these issues?
Like, do you scan for these sorts of things?
They keep me up at night?
Look, there's a whole class of exploits with XML.
There's exploits where you can embed schema information into there and do weird stuff with schema.
I generally think that if you are going to handle XML, you generally whitelist what you accept.
You define your own schema and say, if it doesn't match that schema first, I'm not going to parse it.
I'm only going to parse minimal pieces of it.
There's also, you can use what's called an XML external entity attack where you reference to a schema or an inclusion from somewhere else.
And that somewhere else is relative to your server.
So by getting you to upload a piece of XML, they can try to get your server to load something from your internal network and potentially display it back to the attacker.
So XML can be used as a reconnaissance tool as well.
It's not to say that XML is bad, but you have to follow the advice that is giving you now to use it properly and use it well.
Yeah.
Stay away from the dangerous bits unless you really need them.
And it's rare these days, I think, that you need them.
It seems like, you know, early 2000s, XML was supposed to be the answer to all the questions that involved any form of connectivity, right?
Like we have all these fancy things with XML.
We had all the hype around soap services.
You have XSLT going wild being like the way to generate all sorts of stuff.
And I feel like we've kind of moved on, but there's still plenty of XML processing around.
XML has its place.
It's a great metadata standard with a lot of bells and whistles attached.
The problem is 90% of people don't need those bells and whistles, but it is what it is.
Yeah, I guess I should knock XML.
I mean, it is the main bit of traffic on some of my websites with the podcast RSS feed.
That thing gets hammered.
So I guess I should love XML, but that's the simple version.
So another thing that you put in here that I thought was really interesting is people relying on assert to actually do runtime control.
This one is pretty obscure, actually, and not that well known.
And that is that there's effectively an optimizer.
Well, there's a series of optimizations you can do in Python.
And you can run Python in optimized mode, which does.
I mean, if you look at the history of Python, basically what it tries to do is traverse the syntax tree and kind of make assumptions about how it should be executed.
So that if you're doing it in production, it almost removes commands out of your code and skips them or looks at them differently.
So this is things like constant crushing constants together, loop on folding.
And there's a whole bunch of optimizations.
One of those optimizations is to ignore assert statements because really they should be used for debugging.
So if you're used to any other programming languages, so sometimes you can basically create like a debug assembly or a runtime assembly where they have debug symbols in one.
And it's designed for production and another Python basically has that, but it's by adding an extra flag when you execute the Python file.
So it skips certain commands depending on whether it's running an optimized mode or not.
So if you use an assert statement to do things like checking that the password is right or checking that the user has the right amount of privileges or whatever, then basically it all runs fine in unit tests and integration tests because you never use optimized mode because you always want the assert statements.
And then when you actually deploy it to production, someone says, oh, Python is quicker, like 10%, 20% quicker if we run it in optimized mode.
They switch the flag on and all of your security catches and everything like that just disappear.
Yeah.
I mean, they could be totally sort of silent as well, right?
If you were doing like containers, you could depend upon a Docker container and the base image could change in a way.
They're like, yeah, we made it a little bit better.
It's faster.
Oh, great.
I love faster.
Let's do that.
Wait, why can people be on this page again?
This is terrible.
Yeah, that's pretty scary.
So the fix here is don't do that.
It's like, doctor, it hurts when I raise my arm.
Well, don't do that.
Keep your arm down, basically.
Like just use a if, you know, not admin, raise exception, permission error, or something like that, right?
Yeah, typed exceptions.
Yeah, exactly.
Which is how it's supposed to be done anyway.
Okay.
Another one that's pretty interesting is not as common for the web because of the latency, but it's pretty interesting.
Timing attacks.
Tell us about those.
Anthony, do you want to explain this one?
So timing attacks, there's two really, two little buckets this falls into.
One, if you're doing any form of security sensitive operation, like let's say, for example, you're checking a password is valid.
The way a lot of code works is it might say, well, it will say, well, if the password is too short or too long, then don't bother checking the password, just fail out straight away.
And an attacker can use this to work out.
Well, what is a valid password to decrease the passwords it needs to check?
I see.
So if you're going to do like a dictionary attack and you realize, well, it's zero milliseconds for anything under seven characters, we'll start there.
Exactly.
So if you're doing particularly some cryptography, the idea is it's meant to have an approximately equal amount of time, irrespective of what input you give it.
There's also another set of attacks around time of check, time of update.
So if you're doing certain checks and then doing stuff that depends on those checks, make sure those checks are around the same time in code as they are that you're doing it.
Because otherwise there is a gap between when you do that check, that security check, for example, and when you do that task or that operation that requires a result of that check, that can be exploited too.
So there's kind of two areas here.
That's pretty interesting.
I hadn't really thought of the sort of information leakage around that.
So I want to give a shout out to a Python package that I think just is really amazing.
He talked about password checking and stuff called Passlib.
Are either of you familiar with Passlib?
No, I'm not.
Yeah.
So Passlib is really awesome because, you know, one of the bits of advice is to get a random salt and mix that in when you generate the password, right?
Or when you hash and store the password.
And then also make this computationally expensive to guess.
So Passlib is like, there's like one function of like encrypt and one function like verify.
And it will, you give it a plain text password and it will take that and it will fold it like 150,000 times with custom salt for that particular user.
And then it can check it.
But it takes like, you know, 0.2 seconds to determine whether it's right or wrong.
It doesn't even just check the length.
So it's a really nice way to sort of add a few more layers there.
Yeah.
So the other one I recommended was part of the standard library, but it was only added in 3.5.
And that's a module called Secrets.
And it has a method called Compare Digest where you can basically give it two values and it says, are they equal or not?
So that's where you would say if the actual password equals equals the password the user entered.
And statements like that are the type that can be left open to timing attacks.
So Compare Digest basically makes it impossible to do that.
Yeah, that's cool.
So one piece of advice that I have around if you're doing anything like password management or any cryptography stuff, generally speaking, don't write it yourself.
Use a library off the shelf that other people have used and vouched for because it's very easy to, if you do crypto wrong, it can be worse than having no crypto.
Because for all the false assurances it will give you.
Right.
You think it's fine, but, you know, I don't understand.
I base 64 encoded the password.
They can't get that back out of the database.
Come on.
Of course not.
Of course.
Yeah.
That pass level one that I talked about, by the way, they have like a list of all the support algorithms and the ones they recommend.
And they're constantly checking them.
So I think it's bcrypt and SHA-512 right now that they're using.
It'll be bcrypt and probably the PBK-DF2.
They're the two ones that people tend to recommend these days.
So, yes.
Yeah, nice.
So one that I think is kind of scary because it's an exact opposite or in contrast to what makes Python awesome, right?
Like, you know, import anti-gravity.
It sort of captures the joy of Python where you just import anything and it's just there and it just works.
But it's possible that you could have installed something bad, right?
Yeah, absolutely.
And I think not just install something bad, but the way that Python imports work.
They're really flexible.
You can override all sorts of things, including system like almost language keywords.
So you can override the print function or the assert statement or you can do all sorts of crazy things in imports.
So I think one of the challenges with Python is that if you have a package somewhere in your site packages, basically an import path that does something malicious, it can be very difficult to detect that.
And because your site packages is almost like a tier.
So you've got like a system level one and then you might have a virtual environment one.
And then maybe there's another one that you use as well where you might import stuff from somewhere else in your Python path.
Then when you import something, you never actually know unless you go and check what it's imported.
Yeah.
And it could do really bad stuff like, you know, just while you're talking, I was thinking, OK, so I write a package.
The import statement is effectively execute dunder init.py.
Maybe in that section, I'll see if I could go and find SQLAlchemy or some database connection.
And then I'll monkey patch that over for the connect so I can grab your connection string and then pass it along.
So you think your app is still working or, I mean, there's all sorts of nefarious stuff you could do, right?
Yeah, exactly.
And I think it's just people put a lot of trust in a pip install statement in terms of not only what package they installed, but what dependencies that package had.
And what dependencies their dependencies had and what ended up getting installed and whether any of those have actually polluted your site packages.
So basically, if you're importing even a standard library module, like, is that has something else overloaded that?
And is that import basically changing your global namespace?
This portion of Talk Python to me is brought to you by us.
Over at Talk Python Training, we're building out our library courses, and that library is growing each month.
That's why I want to take a moment and tell you about a special offer we have.
It's called the Everything Bundle.
With it, you get, well, everything.
Every course we have in our library, including the ones yet to be published this calendar year.
Many online training companies have subscriptions and discounts if you buy them a year at a time.
Our Everything Bundle is like a subscription, but it's way better.
With subscriptions, the moment you stop paying, you lose access to everything.
With our Everything Bundle, you keep access to our courses forever.
Any course published the year you bought the bundle or sooner is indefinitely yours, even if you never renew.
Check out what's available at training.talkpython.fm.
And if you're looking for a way to support the podcast, taking or recommending one of our courses is the very best way to do this.
Thank you.
That sort of hints at a really scary scenario because I'm pretty careful what I install, but I don't go and check the dependencies of everything that it depends upon before I use it.
I'm like, yeah, this looks like a reputable package.
I'll go ahead and use it.
But it hints at almost like a supply chain challenge in that.
Imagine I find some not very popular package that something popular is based upon.
And then I go do a PR that sneaks in some extra sneaky dependency.
That is actually the problem that people don't realize.
And so when that gets pushed out to be updated, you update your thing.
All of a sudden, you're indirectly pulling in this thing because some guy was like, yeah, it looks like a good PR.
I'm busy, but we'll take it anyway.
Go ahead.
Yeah, it certainly can be.
So, well, there isn't really one.
Again, like the doctor.
Don't do that.
It hurts when I do this.
Don't do that.
Well, you do reference a service that I'm a fan of.
So tell people about it.
Yeah, so pyup.io basically has a sort of a database of packages and versions of those packages which have known vulnerabilities.
So this links to one of the other things I put in the article, which was not patching your dependencies, which is a pretty common pattern where people say, okay, I'm going to get all my dependencies and then I'm going to do pip freeze or something.
And I'm going to put that into my requirements.txt file.
So I've basically pinned which versions do I know work and no one ever touched that file.
So like that's probably one of the scariest things, as you said, here's all the versions.
These are the ones we tested with.
But no one goes and checks each packages or each dependencies website and sees the notification that says, oh, yeah, sorry.
There's a massive security hole in version 2.9.6.
Please update to 2.9.7.
And it's the dependency, maybe the dependency of your dependencies thing.
Like even if you were crazy diligent and you went and checked all the stuff you installed, that's not even enough.
Yeah, exactly.
So pyup.io basically has a database, a freely available database where you can look up bad versions of packages that exist on PyPI.
And they have a service where they can actually go and scan your requirements.txt if it's on a GitHub repository.
Or they have hooks where you can use it with other services like GitLab.
And if they basically say that there are newer versions available or this is a bad version, then they'll give you a notification.
So I guess that's one of the better ways of approaching the problem.
And this is probably the point in my article that got the most negative feedback from people.
They said, oh, of course, you have to pin dependencies.
Like, you know, you can't just willy nilly install the latest version.
But pyup does it does have version ranges.
There's a there's a PEP for that.
So you can say, you know, I want this minor version.
So I want version 2.8 up to 2.9.
And then if they release a 2.8.1 or 2.8.2, then you'll automatically install the right version.
And if you hope that people use semantic versioning, the API itself and the functionality shouldn't have changed.
And of course, you've got good test coverage anyway.
So you'll catch it.
That's a really good point.
The problem is pip freeze doesn't do that.
Right.
And that becomes a ton of work on your side of things.
I use pyup for my stuff.
Like so the training website, the various podcast websites and a few other things.
I have it hooked up and I will get weekly pull requests.
These three packages have changed and they could be like deep dependencies.
Here's their change log.
Here's here's the new version.
And there's just a PR which patches the frozen packages in my requirements at TXT.
It's really nice.
Anthony, how do you think about this?
Yeah.
So one thing I was going to add is that you can never predict when a package that you thought was good may turn bad.
People might write a package and think, yeah, this version is great.
And then someone somewhere finds an issue with it.
So the key here is a regular monitoring of what you're doing and a regular patch cycle.
Because you said you never know when something's going to happen.
So you need to make sure you're looking for it.
And that turnaround time is as short as possible.
So the focus here is more on your operations.
How do you manage your system as opposed to necessarily how you program it?
But nevertheless, that's important.
Yeah.
I think another step there is you have to proactively be applying these changes.
It's one thing to notice there's a problem.
It's another to notice that PyUp sent me a PR that says, oh, you're depending on this version of, you know, a JSON parser or something.
And it has this vulnerability.
You need to fix it.
It's another to go, yeah, and now I'm patching the server.
You think, look at, what was it, Experian?
Right?
They were hacked with a known vulnerability.
It was, everybody said, this is ultra bad.
You need to drop what you're doing, skip lunch and go fix it.
And it's just, well, we work at this big company.
We can't be bothered to change this because if it breaks, this is not my site.
But if I break it trying to fix it, I'm losing my weekend.
So I'll let someone else deal with that on Monday when they get in.
And then, you know, 143 million people lose all their credit and personal banking details, me included.
Ouch.
Yeah.
But I mean, what are you going to do, right?
I think there's like another layer that goes on top of this.
Like you have to act.
Yes.
I mean, it's a patch management aspect of your server maintenance or system maintenance.
I mean, as Ant said, there's tools inside Python, but you need to use them and you need to be using them regularly.
You need to have that, you know, I do need to fix it now.
So how do I, how do I decrease that turnaround time to as small as possible?
Yeah.
And what do you think about speed to actually deploying the fix?
Like, are there like continuous delivery bits of magic that you people would be willing to rely upon?
Like it says massive security vulnerability.
We will let it automatically publish this if the test pass.
I'm not sure.
I mean, if your test passed, it still needs to go through some sort of UAT.
It depends, I guess, on the, it depends on the project and depends on what it's for.
Like if it's a, if it's an internal web application, then, you know, it's unlikely, but you also want to make sure that thing gets patched and updated as quickly as possible.
The cost of, the cost of, the cost of downtime is one thing, probably smaller than the cost of attack or the cost of compromise.
So I guess it's a, it's a, it's a kind of looking at it from the angle.
Another thing I guess I want to talk about is that the way that you as a developer talk to operations, assuming you, you have an operations team that you're talking to, and that's not just another hat you have to wear.
And the way you talk about what versions of the dependencies your, your package depends on and how brittle that is.
Cause something I've heard a lot is people say, never know, don't touch my dependencies.
Cause I know that they work and it was probably going to break the code.
So from an ops, you know, angle, they're like, well, we're going to look after all the system.
And then we're going to look after all the stuff that's, you know, dev have told us not to touch that and to leave it alone.
Otherwise it's all going to go really bad.
And if, if they touch it and they try and patch something, then the dev team's going to be like, oh, well, you know, you've, you've been changing the code and you've changed the dependencies and we didn't ask you to do that.
And that's why it's breaking.
So I guess it's, it's a conversation between the two teams or if you've got DevOps and then having a conversation about how you try and automate some of that stuff.
Yeah.
The more automation, the better.
So the next one that you have on your article was surprising to me.
I didn't really think about it, but I guess it makes sense.
Is it temporary files?
Yeah.
I'm lucky enough not to have to use those very much in most of the stuff I write these days, but they're actually very common vulnerabilities.
So apparently there's a MK temp function that'll generate a temp file.
I didn't even know about this.
I don't use temp files very much either, I guess.
Yeah.
It's a, it's an old one.
And I came across this when I was doing building the course for moving from Python two to Python three.
Cause one of the recommendations is that you don't use the Python two functions for creating temporary files because they have known security issues in them.
So kind of digging into that a bit deeper.
So there's a temp file module, which is the one that you should use.
And there's a function called MKSTemp, which you should use to generate temporary files.
Is that for secure?
I'm pretty sure S stands for secure.
Yeah.
Nice.
Okay.
So the problem is there could be timing attacks or if you hit the time, just right, like you could create the temp file and then you could swap out the data before they read it or other bad things like that.
Right?
Exactly.
So the reason the old one is bad is because it will create the file first and then it will open and load the file.
So what can happen is someone can sit there scanning the file directory, the temporary file directory.
An attacker can basically sit there looking at it constantly.
And as soon as they see a file pop up, so the file handle is being created, then they can go and dump a load of data in there.
And then you open it and then it's all changed.
Like basically it's a way of them injecting data into your application.
Yeah.
That sounds bad.
So another one, you kind of touched on this before is parsing other file types can be really bad.
And I kind of riffed on XML being bad because it was old and complicated, but YAML is kind of new and awesome.
That probably is bad, right?
You know, this YAML one is so really hardly anybody knows that you can do this because when you look at the example, you think, why would they allow that to happen?
Wait, hold on, hold on.
I think exactly like maybe you shouldn't tell anybody about this because you're going to tell people they could do it as much as to protect themselves against it.
Exactly.
No, I'm just kidding.
Go ahead.
Tell everyone.
So I guess the most popular package for reading and writing YAML files is called PyYAML and it has a method called YAML.load or YAML.loads.
And if you actually read the documentation, it says in big letters, warning, YAML.load is not safe, essentially, because you can run any Python function by putting special characters in the YAML file.
Yeah, like exclamation, exclamation, Python object apply, OS.sys, you know, some form of like Python code or calling some sort of sub process or all sorts of bad things.
Like that's incredible that you can do that, that you can just say, shall execute this in my YAML file.
So you can basically put a special, it's like two exclamation points and then a special path and then the name of the function in the standard library that you want to execute and the parameters.
And then if you call YAML.load and the YAML text or the YAML file has that basically the special syntax in it, it will just execute that locally.
So you can imagine like if you had a web application where you were asking people to provide some simple YAML input to describe something or you were loading something to configure something.
I mean, an example that I used in there was, you know, I use YAML a lot with Ansible, which is like a network automation tool.
And they had a, they had the vulnerability.
They had the same vulnerability because in that product called Ansible Vault, they were loading it using YAML.load.
And people are like, oh, awesome.
I can just like pop a shell on this box instead of providing a password.
That seems amazing.
Anthony, do you use Ansible or work with YAML and worry about these things?
Yes.
I mean, this is, this is a perfect example of something that really, it's like for those, if any of your listeners are familiar with JavaScript, you used to have the eval that used to run to load in JSON, but they changed that to parse because eval was inherently unsafe.
And this is an example of a function, which is just, it just goes on the, on the, on the do not use list for anything that is serious, right?
You just don't use it.
If there's no equivalent on it, then, then we look at something, something else because there's an, unless we go and rewrite it, there's, there's no workaround.
It's basically like giving people like just dollar prompt access, like type here.
What do you want to do on the server?
Exactly.
To be honest with you, this is one of those things.
When I read something like this, the first thing in my head is what were they thinking?
I am with you.
So first.
Yeah.
So, and tell us the fix.
What is your fix here?
Okay.
So there's two fixes and I only found out about the second one yesterday and I think it might have something to do with this article.
The first fix is that you don't use load, use safe underscore load, which.
Of course.
So in the same way that you have to use MKSTemp instead of MKTemp, you should use, however, I guess, explicitly saying you want to do things safely is a bit of an anti-pattern.
So I did see there was a pull request which has been merged into PyYAML to make the safe version the default.
And you have to explicitly ask for the unsafe version.
However, I think that's only been merged in the most recent version of 4.1.
And then if you ignore all of our prior advice about updating your pip dependencies, then you're never going to see that anyway.
These do interplay, don't they?
So I was definitely thinking of that API design sort of experience and like, wait, load and then the safe unload is what you're really supposed to do some of the time.
Like, this does not help people fall into the pit of success, right?
Like, to me, it seems like if you don't know what you're doing, it should default or just lead you down the path of, well, do the safe one.
And if they need the crazy, you know, run this shell thing, like, make them hunt for that.
Don't make that the default until they know better, right?
Sounds like at least they've gotten that working now.
Let go.
Yeah, exactly.
And I mean, the advice that I would give to anybody who is designing their own APIs is security by default.
What you do, the most obvious way of doing things, the standard way of doing things should be the secure way.
If you have features that are potentially unsafe, by all means, expose them that make the developer or the user specifically ask for it so they can accept and manage the risk.
Yeah, that's perfect.
One of the ones that I felt is kind of obvious on this list is obvious because I've been around for a while, I guess, is this concept of pickling.
And pickling is the act of taking more or less a binary version of a Python object graph, putting it on disk, and then rehydrating it back into objects, right?
Yeah, and it's typically used in sort of inter-process or inter-Python version communication or dumping an object somewhere and then loading it again somewhere else.
And so it's kind of built into a standard library.
It's been around for a while.
And before things like JSON kind of became really popular, I guess it's one of the preferred ways of communicating or sharing data between Python processes.
The problem is that it has a number of fairly well-documented security vulnerabilities.
I mean, if you're loading up a pickle file, you can basically put things in the pickle file, which cause it to run any Python process.
Like, if you basically create a new class and then you declare something called dunderreduce, then the contents of the dunderreduce method, if you return back a tuple, you can basically, the tuple that you return can be the name of a standard library function and its arguments.
So basically, that's, again, where you do os.system or subprocess.popen, and you basically pass it all the arguments.
So instead of loading this nice pickle file and you continuing with your day, basically, you load a pickle file and it just runs commands on your local machine.
Yeah, that's not amazing.
So, again, one of these sort of don't do this.
It's extra hard to check, too, because the thing you're delivered is a binary blob.
So how do you know whether it's safe or not?
You can't even look at it.
It's not even like the YAML file where you're like, wait, wait, wait, what is that double, double, double exclamation mark Python thing?
That doesn't look right.
Right.
This is just, you know, one, zero, one, zero, zero, one.
Seems okay.
Yeah.
So there's not really a workaround for this other than don't use pickle or don't try and unpickle things from an untrusted source.
But then I don't even like saying that because it's that kind of assumption which attackers use for using attacks, combining them together.
But Anthony knows a lot more about that than I do.
Yeah, it's chaining them, right?
It's like you lose one to get one layer in and then another and then another.
Yeah.
Ant's got a very good point.
The way a lot of attackers compromise systems is they won't go after the top tier, the most important, the most visible ones.
They'll try to look at maybe the second or third tier systems, ones that people may not have paid as much attention to or made as much effort securing.
And if they can compromise those, they will use those as a foothold to go after things that people perceive as important.
So if I compromise an app and it's communicating via pickles to other apps, for example, that can be how the exploit occurs.
So it's good to keep in mind that every system you write has to consider security, as Ant is saying, and follow Ant's advice on looking at these 10 topics.
Yeah, I mean, maybe this is some wimpy little app that's just like some reporting thing, but you could use it to get behind the firewall or maybe you could pickle some bad stuff into a shared Redis cache that then the other system might read.
And then, you know, you just level up step by step, right?
The so-called lateral movement.
It is being recorded, you're right.
Exactly, exactly.
And look, three, four, five hops for the compromises is not unusual.
And when you see it going, you realize how good some of these attackers actually are.
But I digress.
That's right.
So I guess the last two kind of blend together a little bit in about not patching your Python runtime, sort of the main one, what you get if you just go to the open a shell and just type Python 3 or something, or your dependencies as well.
And I heard that you don't really need to patch your Python runtime because there's zero days that sometimes appear in like your OS.
So you can just like, this is not worth bothering with, right?
What was that crazy comment was about?
I can't remember.
There was a comment on those lines.
They were like, oh, but why do we bother?
Why do we have to patch Python?
Because they're probably just going to hack us anyway.
So what's the point?
If only.
If only it worked that way.
I think that's, I mean, we touched on that at the beginning a little bit.
And that is sort of a sense of despair that people have.
You're like, look, I could do all these things that I'm supposed to do.
But soon as there's some sort of zero day or O day in my system, you know, all bets are off.
I'm not going to be able to defend against that.
I don't know what zero day there is in, you know, NGINX unit.
And so forget it.
I'm just not going to worry about security.
And I can totally understand how people feel that way.
But there was some interesting analysis and reports saying that even state sponsored actors of hackers and stuff primarily use super boring stuff, like all the things we've already been talking about, right?
Like SQL injection and other boring unpatched things.
I mean, zero days, yes, they happen.
But as a proportion of total security incidents, they're actually relatively small, particularly for the well-known, well-trusted packages and products that are out there.
I think this is one of those cases where people need to get their own house in order before they throw stones, if you know what I mean.
Yeah, yeah.
But I mean, once again, I mean, most of this stuff is relatively simple once you understand what you need to do.
So it's just a question of putting time and effort into it.
That's all.
I think there's a difference between the NSA or some other country is trying to literally get into your thing or I'm on the Internet and people are rattling the doors to see if they're open.
And they're not going to spend a full week trying to get into my system because they know there's thousands that just have SQL injection or some other random thing, right?
Yeah, and look, to be honest with you, if the NSA really, really wants to get into your network, the version of the Python package you're using is probably the least of your problems at the moment.
So...
Yes, exactly.
Exactly.
Plenty scary, but we're not going to think too much about that, I guess.
So what you're telling me is I need to install Python 3.7 because it just came out.
Things like that.
Yeah, I'd actually say, this is probably controversial, but I wouldn't install Python 3.7 until 3.7.0.1 comes out.
Generally, I'd...
Yeah, yeah, sure.
But maybe, Pat, like if there were like 3.6.6 or 3.6.7, whatever the next one there is.
3.6.6, yeah.
I'd go with 3.6.6.
But it's part of that staying on top of things.
I wish PyUp actually had a check to say your Python version is 3.6.6 and it should be 3.6.7 or something like that.
There is another tool, which is open source as well, called InSpec.
And it's made by the same people that brought you Chef.
So it's built in Ruby, but it does actually have a bunch of hooks for Python applications.
And I know that it does do virtual environments and also checking versions of packages in production.
So you can say, make sure that none of our servers in production have this version of Python.
Make sure that they don't have these versions of these packages as well.
And you can do that in InSpec and basically declaratively saying, here's our security rules.
And it will go and scan through your installations for you or your service for you and actually give you back a report.
So InSpec, I guess, would be the way to do it or a tool like that.
Yeah, that makes a lot of sense.
All right.
Well, I think hopefully people learned a lot from those 10 items.
I mean, there's certainly a couple of them that I had heard of, but others were new to me.
And it's always good to be aware of these things.
So thanks for putting that together and both of you for sharing it here.
So Anthony, how do I sell this to my, you know, I work at a startup.
The management just got VC funding.
We're supposed to do growth, growth, growth.
We're trying to figure out new features so that we get this thing to get out.
How do we get ourselves to worry about this?
So, well, the first thing is to understand any legal or contractual obligations that you have.
So if you're in Europe, for example, you have to follow the GDPR, the new general data protection
regulation that's there.
If you're handling credit cards, for example, you've got PCI DSS, the payment card industry
data security standard.
These are the non-negotiable things you have to do.
The second thing is if you have any security executives or leaders in your organization,
a CISO or if they have corporate policy, security policies need to follow.
They're two things.
But beyond that, one is just look at the newspaper.
Reputational and financial damage is real.
It happens.
We've all seen or heard of companies that have been hacked and thinking, gee, I wish I weren't
them.
I wish I was not them.
So don't.
Don't be them.
Exactly.
Well, and also I think it comes to do with culture a little bit, right?
Like if the culture is do not change this application, do not touch it, because if you break it, you're
going to take it down some part of our business and we're going, it's going to be so bad that
that thing ossifies.
And it's basically like, no, it's kryptonite.
Nobody wants to touch it.
I'm going to stay away from that.
Yeah, it probably is got some security issues, but I'm not touching it because I will be
punished to no end if I'm the one who breaks it.
I can see that happening a lot.
Yeah, it is.
And this comes down to your general culture around, as Ant said, test coverage, refactoring.
If you have stuff that you can't touch, it's going to cause you security problems.
If it's stuff that you can touch, you have a fighting chance of solving them.
So that comes down to, once again, to the term that uses risk management here.
Is your management happy to accept the risk that you're going to have an app that will
eventually cause you a problem?
Right.
It's sort of the consequence of failure there.
I mean, look at WannaCry and Windows XP on a lot of these things.
There's so much damage from that, right?
Yes.
And particularly if you're in a small shop, if you're in a startup, reputation is big early
on.
So you need to make sure that you can maintain that trust that you're going to need from your
first few customers.
Yeah.
And you probably have an advantage in the sense that you don't have big data centers with legacy
machines laying around.
You're probably on the cloud using modern tools because you just started.
All right.
Chances of keeping that upgrade train running is probably easier.
Exactly.
It's all greenfield.
You don't have to keep older stuff running.
Exactly.
Yeah.
All right.
We're getting pretty short on time and I'll be respectful of both of your times, but maybe
you could tell us really quick some places to learn more about security.
Yeah.
I guess one, two projects I want to call out.
So there's a number of projects with the same kind of name that's related to goats.
I'm not sure where the goat name came from originally, but basically there's a project called
Web Goat, which was originally done as a how not to do things, open source project to basically
include all of the top 10 most common vulnerabilities.
And I can't remember what language it was written in, probably Pearl, but there's a Python version
called PyGoat and there's a Django specific one called Djangoat, which I guess we'll have
in the show notes.
But if you actually look at that, it's got all the Djangoat ones really cool.
It's got all the stuff you should never do with Django projects like leaving debug enabled,
for example.
But basically how to do the, all the kind of vulnerabilities we've talked about as well
as the other ones in a project.
So it's kind of like a how not to do things project.
And I think it's good if you want to learn how things are done.
And also it has instructions about how to break it, how to use those vulnerabilities.
So I would start there.
And then if you know them, then you can start doing things like doing scans through your source
code for those particular types of vulnerabilities or those functions and seeing if you can find
bugs in other places.
Yeah, that makes a lot of sense.
I really like this goat series.
That's pretty interesting.
One thing I want to give a quick shout out to that's in your neighborhood and is a podcast
called Risky Business.
Have you heard of it?
I listen every week.
Yeah, I love it.
It's fabulous, man.
Those guys do such a good job.
It's like headline news in security and tech programming security.
It's really great.
And just listening to that, you learn a lot sort of by osmosis, I think.
All right.
Well, I think just we're out of time.
We could go on and on and maybe we'll have to do another episode on this.
But that was really helpful and insightful.
So thank you both.
Since there's two of you, I'm going to ask two questions at the end, but the same one.
We'll just do the notable PyPI package.
So is there a package, maybe related to security that people maybe haven't heard of,
but you want to throw out there to let people know about it?
Anthony, you want to go first?
I had a couple, but if one of those things that I think rather than a package, I think people need to take a step back and realize that security is a mindset here in that there's no package that's going to make your app secure.
So I'm going to twist the question a little bit here.
It's about keeping abreast of what's going on and keeping current and continuing to learn.
And it's an area that can be fascinating, can be really interesting.
Yeah.
Excellent.
And?
Yeah.
This one hasn't actually been released yet, but Brian and I are working on a new pytest plugin called pytest Requests.
And by the time this episode goes to air, it'll be out and it'll be wonderful.
So I'd recommend you check it out.
Oh, that sounds really fun.
That's awesome.
And also, I want to give a shout out to your Python 3.7 course.
You just did a new course on Python 3.7.
I thought it was great.
Thanks.
Yeah, that just came out just in time for the actual release of 3.7, which is good.
Yeah, you beat the window by like a week or something.
Maybe just tell people super quickly where they can get it and what it's about.
So the course is on Pluralsight.
If you have access to Pluralsight or you want to sign up for a trial, you should be able to watch the course.
It's less than an hour.
And I basically go through all the major new features in 3.7, how to use them, how they work, how to configure them, as well as some of the other benefits.
So it'll take an hour of your time and you'll be a Python 3.7 expert by the end of it.
But you should wait till Python 3.7.1 to actually get going, maybe?
Probably, but that'll be weeks away, I reckon.
I reckon, yeah.
I already installed 3.7, but I have 3.6 on my machine just in case I need it.
All right, awesome.
Well, yeah, I enjoyed it.
So good to let people know about that.
All right, both of you, final call to action.
People, maybe they're thinking about the software that they have.
What's the first thing to do to start to address this?
Anthony?
The first thing is to take a step back and think, well, what is the most important things that my app is protecting?
What are the most important business processes or data that's there?
And to think, how can I protect it?
How should I protect it?
Is what I'm doing what I need to do?
All right, excellent.
Anthony, anything to throw in on that?
Yeah, I'd say just don't be intimidated by security in general and just start simple and be willing to learn and also be willing to learn from people who have a lot more experience, of which there are plenty of people out there.
Yeah, it's definitely a different way of thinking and it's pretty fascinating.
All right, well, thank you both for being on the show and sharing all this stuff.
It was great.
Thanks, Mike.
Thank you, Mike.
Great to be here.
Yeah, bye-bye.
This has been another episode of Talk Python to Me.
Our guests on this episode have been Anthony Shaw and Anthony Langsworth.
And this episode has been brought to you by the Test and Code podcast as well as Talk Python Training.
Keep up with the latest news and become a better developer by listening to Python Bytes at pythonbytes.fm and Test and Code at testandcode.com.
Want to level up your Python?
If you're just getting started, try my Python jumpstart by building 10 apps or our brand new 100 days of code in Python.
And if you're interested in more than one course, be sure to check out the Everything Bundle.
It's like a subscription that never expires.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.