Now we’ll go into making outbound calls. This is pretty similar to SMS but does get more advanced pretty quickly. Now is the time where being Internet-reachable is a necessity.
First, how to create a call. For this I’m going to make the functions easy again:
@app.route("/voice/") def voice(number): try: client.calls.create(url="http://ip_address:5000/who/%d" % number, to="+1%d" % number, from_=TWILIO_NUMBER) return "Call sent." except TwilioRestException, e: return "Unable to send. Reason: %s" % (e.msg)
This is very similar to our SMS method with the exception being “client.calls.create” instead of “client.sms.messages.create”. Also, instead of passing a message to the user we are passing a URL to forward them to. While you don’t have to pass a URL, there does have to be something for Twilio to process (which will be covered shortly). So, basically, when the call is created Twilio will read special XML generated at /who/[number] and go from there (there’s a few options, we’ll cover the basic message reading first). Here’s the method for /who:
@app.route("/who/", methods=['POST']) def who(number): token = generate_token(number) xml = TwiML.Response() xml.say("Your token is: %s" % ". ".join([i for i in token])) return make_response(str(xml), 200)
Twilio only POSTs when itself is referencing a URI/URL, so that is why we only support POST for /who. I won’t go into the basics of TwiML (Twilio’s XML), but basically what’s going on is we are creating a reference to our response XML, and then passing it what we want it to read back to the user. From my experience, if HTTP response is not 200 then you will run into issues, so that is why we force a 200 (HTTP OK) response regardless.
The reason why we rejoin our token like we do is that if we gave it as one long strong then Twilio’s text-to-speech service would jumble it all up. If you just space the characters apart it reads still a little too fast. So we instead make Twilio read each character as if they are a sentence by themselves.
Visit http://ip_address/voice/verified_number (replacing “verified_number” with your verified number like with SMS) and give it a try!
This will be a small blurb compared to the rest but this is rather essential. This isn’t the best way to generate tokens and in no way do I recommend you use this in a practical case. Here is the code, however (place it just below the app = … line):
def generate_token(number): from time import time charlist = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890+/=" num = str(number+time()).split(".") info = [num[i:i+2] for i in range(0, len(num), 2)] token = "" for i in info: index = int(i)+int(i) token = "%s%s" % (token, str(charlist[index])) return token
Basically what this does is add the current time to the number provided (and since time() returns a decimal we only want the whole number). Then we split the number into multiple pairs and add both digits in the pairs, and that is our place in the token list/charlist. It’s pretty simplistic but it does our job just fine.
When I wrote the original code I made things way too complicated for it. So, I’ll steer you in the direction of NOT doing that, and we’ll make this simple!
After our import lines, add these:
TWILIO_SID = "xxx" TWILIO_AUTH = "yyy" TWILIO_NUMBER = "zzz"
The xxx and yyy will be replaced by whatever values you noted down/get from the Twilio dashboard. You also need to set your Twilio number as well so the service will know who to set the “From” field to.
Now we need to create a reference to Twilio’s API, which also requires us to send the SID and AUTH values:
client = TwilioRestClient(TWILIO_SID, TWILIO_AUTH)
We’ll work on SMS first since its cheaper and easier to work with. First what we need to do is create a route for SMS:
@app.route("/sms", methods=['GET', 'POST']) def sms(): try: client.sms.messages.create(body="Huzzah!", to="+1xxxyyyzzzz", from_=TWILIO_NUMBER) return "SMS sent." except TwilioRestException, e: return "Unable to send. Reason: %s" % (e.msg)
For sake of this project right now replace the hard-coded number “+1xxxyyyzzzz” with the number you signed up for with Twilio (demo accounts can’t send to just any number, paid accounts can) and visit /sms to receive a text message. Pretty cool, huh?! Lets change this a little bit and make it so when a GET request is made to the page it’s sent to a number specified. Here’s the new code block:
@app.route("/sms/") def sms(number): try: client.sms.messages.create(body="Huzzah!", to="+1%d" % number, from_=TWILIO_NUMBER) return "SMS sent." except TwilioRestException, e: return "Unable to send. Reason: %s" % (e.msg)
We made some changes here. First, we removed the ‘methods’ argument to app.route. This was done because we want to just focus on handling GET requests right now, which Flask defaults to when methods is not passed. Next is the route. Now we need to visit /sms/10-digit-number-here to make it work (replacing the “10-digit-number-here” part with the verified number). We still need to pass that info to the method itself so we can use it, and also modify the ‘to’ field so it still sends properly. Now, try again and it should still work!
What we need is something to handle HTTP requests. Thankfully Flask does this for us and is extremely easy to use!
First thing we’ll do is import all of the stuff we need/want:
from flask import Flask, request, redirect, make_response from twilio import twiml as TwiML, TwilioRestException from twilio.rest import TwilioRestClient from db import * from peewee import SelectQuery
This imports the important Flask and Twilio options as well as our database reference. Now we need to initialize Flask before we get too happy:
app = Flask(__name__)
In a way you can think of this as like using logging.Logger(), you typically pass it __name__ so that it has a reference.
Now, lets make it so when we go to http://ip_address:5000/ we see a message:
@app.route("/", methods=['GET', 'POST']) def main(): return "You sure?!"
The method name is irrelevant (though has to be unique per route). The “/” is the same as when visiting http://ip_address:5000/, and we will let the main handler support both GET and POST requests. Now, when you visit the URL you’ll receive “You sure?!” in your browser.
After, we need this two-liner:
if __name__ == "__main__": app.run(host='192.168.0.102', debug=True)
However, change the IP in host to one that is reachable from the Internet (or set up port forwarding) so later on Twilio will be able to connect to the web service. Now, open up your browser once you run the script and you should see the message.
This was short but, then again, there’s not a whole lot that needed to be covered to get Flask up and running by itself. Next, however, will be when the fun starts and we work with Twilio’s helper library.
Lets figure out what we need to make this magical wonderland happen. We need a user’s phone number, a field to state if the phone is usable or not (if we should concern ourselves with requests from it) and storage for the active token. If we want to make it more advanced than we will but for now this is good. So we will use two tables: phone and tokens. The token will be based on the phone number and current timestamp as sort of a salt (not the safest but again, template for the future ).
id – primary key
digits – small integer (15-digit number)
id – primary key
token – variable char (length 0f 10)
phone_id – foreign key to phone->id
Simple, eh? Now lets create it in Python!
from peewee import *
database = SqliteDatabase(“2fa.db”)
We import everything of the Peewee library to make things easier on us. We also specify we want a SQLite database.
database = database
We create an abstract base class (ABC) so everything can share the database instance. This is mostly done to save typing.
id = PrimaryKeyField()
digits = IntegerField()
id = PrimaryKeyField()
token = CharField(max_length=10)
phone = ForeignKeyField(Phone)
Specify the table structure of the phone and tokens tables, subclassing the mentioned ABC class.
phone = Phone
tokens = Tokens
Easy references for the tables (which will be needed quite a bit).
Connect/load the SQLite database.
Create the tables in the SQLite file.
Save the above code fragments to a file called “db.py” (otherwise make the adjustments in later parts). Now we have the database laid out properly and easy to work with!
For the point of this guide we are going to be using just our test account number. The only difference between that and a purchased number is that every SMS or call is prefixed with a “Thank you for using Twilio” kind of message. For demo’ing everything its a small price to pay. I’ll also be walking through this with you as well by creating a new account.
- Sign up for Twilio here: https://www.twilio.com/try-twilio and enter the appropriate information.
- It’ll prompt you for a phone number so they can verify who you are (i.e.: a bot wasn’t programmed just to sign up for the service), enter your phone number. I used Google Voice and had no issues. You’ll receive a text message with a verification code. Enter that.
- Twilio will generate a phone number for you, you can either use the one provided or search their database for a specific number.
- Once you pick a number it’ll let you test some of its basic features. Its helpful to make sure everything works fine at least.
- Click on “Go To Your Account” and you’ll be presented with a pretty nicely done dashboard
In the dashboard make a note of your account SID and auth token (hover over the little padlock icon and click it to make it visible). You’ll need these later, SID being your account ID and the token being the SID’s password (so keep it a secret!). There’s a lot of useful information Twilio gives you and its awesome. But, lets continue on. You don’t need to do anything else in the dashboard yet. Now we’ll get started on our web service so we can make magic happen!
Just like everything else with IT security, once a gem is found everyone jumps on it. Originally I was going to offer this as a service for my business (still might to a degree), but instead thought I’d share with the Internet how to create yourself a beneficial two-factor authentication system. In the end, you’ll be able to validate authentication requests either via SMS or voice and be proud of the extra power!
While there’s few requirements for this, they should still be addressed:
- SMS & Voice Provider: Twilio
They have been around for a while and give you $20 worth of credit to use for your test number when you sign up. This should be far more than enough for your use as 1 SMS = 0.75 cents and 1 outbound call = 1 cent. While it does cost to also have a number ($1/month/number) its still a valuable service in a small market. Also note that pricing is relative to when I wrote this.
- Language: Python
I am not a pro at Python but it is the easiest I have ever worked with thus far. It also is easier to deploy on various systems.
- Help Libraries: Flask, Peewee and Twilio
Flask is used to process web requests (i.e.: make our Python script act like a minified web server) and Twilio has a Python client/module/helper library that helps us tie very easily into Twilio’s REST API. Peewee makes database connections and such A LOT easier. I won’t go into the mechanics of it but basically its an ORM (object-relational mapper).
- Database: SQLite
Any database will do and I’ll just be covering the table layout here (fields, types, etc…). I’ve since used PostgreSQL after I stopped writing this code and if I did it again I would choose PostgreSQL in a heartbeat. But for a starter guide SQLite is great. After all there’s not a lot of fancy work that needs to be done here.
A sort of pain the butt aspect of Twilio, however, is that numbers have to be in E.164 format. Essentially what this means is that any numbers (even your own Twilio one) that are passed through the Twilio client must be in the format of “+[country code][area code][rest of digits]” so if your Twilio number is 1.234.567.8900 then when you use the API it’d be +12345678900. While its not a big deal it can be annoying to work with at first.
I don’t suggest using the code as is for public use. This was intended for such but back then I was still in the infancy stage. However, this code can be used to build your own as I intend on those who are reading it to take what’s given and run with it at the end.
This guide assumes you have all the mentioned required stuff installed and ready to go.
Twilio does have a tutorial and code for creating a two-factor authentication system using their backend. The major difference between my code and theirs, however, in terms of purpose anyways is that mine generates a random token that has to be entered. You’ll see more of what I’m talking about when we get deeper into everything. The next part will cover setting up Twilio for use.
A recent article on Slashdot discussed the aspect of Google requesting to start using dotless TLDs. While ultimately ICANN denied this request, its interesting to see where the future of the Internet very well could go.
Most filter systems use wildcards but not to a scalable extent (in such a way that future concerns are taken care of as well). It does make sense in some aspects, though. How is anyone to know that dotless domains will ever happen, for example. Another issue is that filtering through a long list of futuristic ideas still adds more overhead to each request, which even when cached can pose some annoyances.
Should filtering be done on a whim, when new techniques/resources are made available or when its best suited for the network? Its tough to say.
When building a LAN you could easily tell the filtering system to deny any requests to *.onion, but then you have to consider how likely it’d be to even set up a Tor node within the network, have it connect successfully and allow applications like web servers. If all of these are also possible then you have more concerns than just filtering which domains are accessible.
TrueCrypt is a very popular option for encrypting data, while dm-crypt+LUKS (LUKS is a module for dm-crypt) is an unsung hero of sorts for those who don’t want to install a lot of software.
- TrueCrypt allows encrypting an entire hard disk, while I haven’t found a way for dm-crypt to do this
- Both allow you to create containers to store data
- Neither allow expendable containers (unless TC has changed that)
- Process of creating a container in dm-crypt is more troublesome than with TC
- TC allows for more encryption options out of the box, while dm-crypt may allow more with additional effort
- dm-crypt does not require administrative rights (except for probably mounting)
There will always be people who make a mountain out of an ant hill. However, it hits me in a sore spot when people like to make a simple issue seem like Armageddon.
The Register posted an article about an ISP monitoring mouse traffic on their support pages. The headline of it makes it seem like they’re monitoring all traffic going through their wires, while when you read the article itself its just about them monitoring mouse clicks and activities on their support pages. Why should this be considered a security threat?
I’m not aware of The Register’s credibility but this has greatly hurt it for me personally.
While I can see some uproar about it simply because the end-user’s activities are being monitored, its not as if they are logging key strokes and sending them to the NSA (oh, wait…). They’re seeing what pages are being read, what bounce and exits are being done, etc… Hell, Google Analytics does this for you for free. Its becoming just a little too much for me to handle at the moment with everyone crying wolf without even knowing what sheep look like.