Now that you've gotten your feet wet with our Asterisk@Home series, we want to catch our breath today and make sure your system is locked down. After all, you don't want the entire world making free phone calls on your nickel! Just as unsecured SendMail servers can be used as SPAM relay hosts, misconfigured Asterisk® servers also can be used as relay hosts to place calls to anywhere by anybody. In our second article we covered the basics of resetting all of the default passwords that come with Asterisk@Home. If you skipped that step, now would be a great time to be sure you've changed ALL of them. Just go back and reread the Securing Asterisk section of that article for the details.
Update: For the latest information, please read our Primer on Asterisk Security.
One of our few criticisms of Asterisk is its support of the goto command coupled with undocumented context subroutines and macros which are scattered across more than a dozen configuration files in applications such as the Asterisk Management Portal (AMP). For those of you that cut your teeth on the BASIC programming language, you know the tendency of applications to turn into spaghetti code, i.e. code so convoluted with goto's and undocumented subroutine calls that it's difficult to trace how an application actually plays out when it's executed. This, in turn, makes it extremely difficult to secure such applications because of the complexity of tracing through all the hoops executed when the program is in use.
Particularly for home or small office use, the major security risk with an Asterisk system is incoming call vulnerability. Someone connects to your system through the Internet and then places an outgoing call through your system to a coconspirator on some desert island on the other side of the globe that legally charges $12.00 a minute for calls. Cruise ships charge about the same thing! If you're not careful, you get stuck with the phone bill. Our solution to this incoming call vulnerability is to circle our wagons and strictly limit the number of Asterisk contexts used to process incoming calls. If you're lost in the ozone at this point, don't worry. Just keep reading, and we'll walk you through what all this means and what you can do to easily protect your system.
In Asterisk@Home, the context that controls incoming calls via IP is [from-sip-external] which can be found in extensions.conf using AMP->Maintenance->Config Edit. We previously showed you how to set up a Stealth AutoAttendant. We strongly recommend you use that or something similar to manage all incoming calls to your Asterisk server. This is the main reason we recommend against DID routing with Asterisk@Home. Using a single AutoAttendant assures that every incoming call lands in the same place and callers can only do the things you permit in this one context. Keep in mind that any extension command you have set up anywhere in the [from-internal-custom] context can be executed using this AutoAttendant. It doesn't really matter whether it is above or below the AutoAttendant code! And, of course, if you provide access to Asterisk's DISA service with either an insecure password or no password or if you took our advice and built speed-dial numbers but the calls are routed to Hong Kong, then you're on your own. IT'S YOUR PHONE BILL!
Why did we place the AutoAttendant code in the [from-internal-custom] context? Because we needed access to it for our Sipura SPA-3000 to handle incoming PSTN calls. In summary, you just need to be careful what options you provide in your AutoAttendant and the remainder of the [from-internal-custom] context because anyone can call you and choose any available option throughout that context. And keep in mind that your phone doesn't necessarily ring when someone hits your AutoAttendant so you may not know your system is being attacked unless you review your call logs frequently: AMP->Reports->Call Logs. Remember, any other Asterisk server on the planet can call your server via an IP connection. All it takes is the domain name or IP address of your Asterisk server, and they can at least attempt to make a connection. The only question is what can they do once they get there. And that's up to you! Finally, you need to carefully test your system by placing calls to yourself and pressing every button on your phone including 0, *, and #. Then try placing calls to local and long distance numbers while the AutoAttendant is playing. If they go through, you've got a problem. Last but not least, go into your VoiceMail system (just as a caller would) and dial the same numbers as above making sure there is no back door there that you don't know about. Remember, we showed you how to open the DISA backdoor in VoiceMail so make sure all of your voicemail passwords are secure if you implemented that tip.
Assuming you have deployed the Stealth AutoAttendant and added it to your [from-internal-custom] context in the extensions_custom.conf file, here is our recommended configuration for the [from-sip-external] context in the extensions.conf file. Be sure every other line in this context is commented out with a semicolon at the beginning of each line. Then restart Asterisk.
exten => _.,1,Wait(1)
exten => _.,2,Goto(from-internal-custom,111,1)
Our personal preference is to create a duplicate AutoAttendant context for your incoming VoIP connections. This eliminates the risk of inadvertently exposing some other extension code lurking elsewhere in your [from-internal-custom] context with IP connections. This new context can use identical code to the Stealth AutoAttendant we previously built, or you can customize it as desired. Place the new context at the bottom of the extensions_custom.conf file and then adjust your [from-sip-external] code to look like the following. Don't forget to restart Asterisk.
exten => _.,1,Wait(1)
exten => _.,2,Goto(from-external-custom,s,1)
Update: If you want to retain the flexibility to use the Asterisk Management Panel's DID Routes functionality to map incoming calls from certain trunks to different contexts or extensions, then insert the following code just below the [from-sip-external] label:
include => ext-did
And here's the sample code to insert in your extensions_custom.conf file. If you cut-and-paste the code below, don't forget to replace the opening and closing typographic quote characters with the standard quotation mark character or you'll get unexpected results with Asterisk.
[from-external-custom]
exten => s,1,Zapateller(answer|nocallerid)
exten => s,2,Wait(1)
exten => s,3,SetMusicOnHold(default)
exten => s,4,GotoIf($["${CALLERIDNUM}" = ""]?who-r-u,s,1)
exten => s,5,GotoIf($["foo${CALLERIDNUM}" = "foo"]?who-r-u,s,1)
exten => s,6,GotoIf($["${CALLERIDNAME:0:9}" = "Anonymous"]?who-r-u,s,1)
exten => s,7,GotoIf($["${CALLERIDNAME:0:7}" = "Unknown"]?who-r-u,s,1)
exten => s,8,GotoIf($["${CALLERIDNUM:0:7}" = "Private"]?who-r-u,s,1)
exten => s,9,GotoIf($["${CALLERIDNAME:0:7}" = "Private"]?who-r-u,s,1)
exten => s,10,GotoIf($["${CALLERIDNUM:0:10}" = "Restricted"]?who-r-u,s,1)
exten => s,11,GotoIf($["${CALLERIDNUM:0:4}" = "PSTN"]?who-r-u,s,1)
exten => s,12,DigitTimeout,3
exten => s,13,ResponseTimeout,3
exten => s,14,Background(custom/welcome)
exten => 0,1,Background(pls-hold-while-try)
exten => 0,2,AGI(directory,general,ext-local,${DIRECTORY:0:1}${DIRECTORY_OPTS})
exten => 0,3,VoiceMail(204@default)
exten => 0,4,Hangup
exten => 1,1,Background(pls-hold-while-try)
exten => 1,2,Dial(local/222@from-internal,20,m)
exten => 1,3,VoiceMail(204@default)
exten => 1,4,Hangup
exten => 4,1,Authenticate(1234588)
exten => 4,2,Background(pls-wait-connect-call)
exten => 4,3,DISA(no-password|from-internal)
exten => 2XX,1,Background(pls-hold-while-try)
exten => 2XX,2,Dial(local/${EXTEN}@from-internal,20,m)
exten => 2XX,3,VoiceMail(${EXTEN}@default)
exten => 2XX,4,Hangup
exten => 2XX,103,Voicemail(${EXTEN}@default)
exten => 2XX,104,Hangup
exten => t,1,Background(pls-hold-while-try)
exten => t,2,Dial(local/204@from-internal,20,m)
exten => t,3,VoiceMail(204@default)
exten => t,4,Hangup
exten => o,1,Dial(local/204@from-internal,20,m)
exten => o,2,VoiceMail(204@default)
exten => o,3,Hangup
exten => i,1,Playback(wrong-try-again-smarty)
exten => i,2,Goto(s,16)
Here's how the AutoAttendant code above works. Pressing zero activates the directory, pressing 1 rings the ring group (222) for all extensions, pressing 4 gives access to external dial tone if the password 1234588 is correctly entered, pressing no key (the t timeout entries) rings the main home phone extension, 204. Users can also enter 3-digit extension numbers beginning with a 2. If you didn't insert the following two contexts from our previous Asterisk column, then you'll need to add them to the bottom of [from-external-custom] to manage callers without CallerID:
[who-r-u]
exten => s,1,Background(privacy-unident)
exten => s,2,Background(vm-rec-name)
exten => s,3,Wait(2)
exten => s,4,Record(/tmp/asterisk-stranger:gsm|5|15)
exten => s,5,Background(pls-hold-while-try)
exten => s,6,Goto(ext-park,70,1)
exten => s,7,VoiceMail(204@default)
exten => s,8,Playback(Goodbye)
exten => s,9,Hangup
[ext-park]
exten => 70,1,Answer
exten => 70,2,SetMusicOnHold(default)
exten => 70,3,SetCIDNum(200|a)
exten => 70,4,SetCIDName(Parked Call Info|a)
exten => 70,5,ParkAndAnnounce(silence/9:asterisk-friend:/tmp/asterisk-stranger:vm-isonphone:at-following-number:PARKED|40|local/204@from-internal|who-r-u,s,7)
exten => 70,6,Hangup
MySQL Security Alert. Recently, we happened to look at how security was set up on MySQL with Asterisk@Home. This may also apply to those using plain-old Asterisk with the Asterisk Management Portal. In any case, you need to check your system NOW! Using the Asterisk Management Portal, go to AMP->Maintenance->phpMyAdmin. Then click on the Database pulldown in the left pane and choose mysql. When the tables display, click on the user table. Now click the Browse tab at the top of the right pane. The entry we care about is the second one: asterisk1.local for root user access. If your password field is blank, you've got a potential security problem. What this entry means in layman's terms is anyone on the Internet can connect to your MySQL databases as root with no password. The only roadblock is being able to spoof the default hostname of your Asterisk@Home server. And hostname spoofing has been a reported vulnerability of MySQL so it's just not worth taking a chance. Keep in mind that all of your VoIP account usernames and passwords are stored in a MySQL table when you use the Asterisk Management Portal (AMP). Not a healthy situation when it's your wallet that's at risk. To fix the problem permanently, just click on the pencil beside the second record. When the record displays, click on the function pulldown in the password row and choose Encrypt. Then make up a password that's secure and enter it in the password value field. Click Go to save your update. Now click the Browse tab again and be sure an encrypted password is shown for both root user entries in the table. We don't care about the blank password for the blank user because you'll note that all the database privileges are set to N for this account. Fixed!
Other Security Advisories. We also recommend that you frequently review the Secunia web site for Asterisk security advisories. They also have an RSS Feed for those of us who are forgetful.
Other Asterisk Articles. There are numerous additional articles in this Asterisk HOW-TO series to keep you busy. You can read all of them by clicking here and scrolling down the page. We recommend reading the articles from the bottom up so that the learning curve is less painful. Sleep well. Your Asterisk server is now at least a little bit more secure, and you know a good bit more about how the pieces actually fit together and why.
I secured the mySQL database as you suggested above, but now AMP fails with: [nativecode=Access denied for user ‘asteriskuser’@’localhost’ (using password: YES)] ** mysql://asteriskuser:amp109@localhost/asterisk
I really don’t know enough about mySQL. Is there a way to recover this?
[WM: Doesn’t sound like you modified the password for the correct record. There is no asteriskuser record for asterisk1.local, and that’s what’s giving an error in what you quoted above. The correct record was user root for asterisk1.local, and only if the password field had been blank. Try to access PhpMyAdmin with a web browser directly using http://YourIPaddress/maint/phpMyAdmin/. If you can get in, goto the mysql database, the user table, browse and (carefully) edit the localhost/asteriskuser record and see what’s entered as the password. The password should be 574b6f1662368572 at least for AAH 1.5 and AAH 2.5 (and probably the versions in between).]
Yep, I think you’re right. I managed to somehow fix the problem last night by using these directions: http://dev.mysql.com/doc/refman/5.0/en/resetting-permissions.html.
I went back in following your directions again and noticed that the entry I SHOULD have changed was the third line (asterisk1.local), not the second (the first and second are both localhost, with users root and asteriskuser respectively). I’m nervous about touching anything in there at this point though! Also, both asterisk1.local and localhost (next line) show blank User now, and all privileges set to N. Is that how it is supposed to be?
Also, I don’t know if this is related (not sure when it started either) but I’m also still seeing the following:
== Parsing ‘/etc/asterisk/manager.conf’: Found
== Parsing ‘/etc/asterisk/manager_custom.conf’: Found
== Connect attempt from ‘127.0.0.1’ unable to authenticate
Thanks again for all your great articles – this has been a huge help in getting me going. I never would have attempted without your guide!
Help! I have the Marriage Made in Heaven with Sprint PCS working just great. The only problem is that I can’t use my stanaphone number and direct other (non-cell) to an extension. I’m sure I have to modify the from-sip-external context as the only thing in there is to route calls to the custom-disa. What can I do?
I was actually googling around for password encryption in voicemail.conf. Can you address that issue as well? I’m really stumped about how passwords can be stored in an encrypted form in voicemail.conf.
[WM: The short answer is YOU CAN’T and there are lots of other Asterisk passwords floating around your machine that aren’t encrypted either. Bottom Line: Make darn sure you have a very secure root password and don’t add any other user accounts to the machine.]