Use the correct ical.h file
[asterisk/asterisk.git] / README-SERIOUSLY.bestpractices.txt
1 ==================
2 | Best Practices |
3 ==================
4
5 The purpose of this document is to define best practices when working with
6 Asterisk in order to minimize possible security breaches and to provide tried
7 examples in field deployments. This is a living document and is subject to 
8 change over time as best practices are defined.
9
10 --------
11 Sections
12 --------
13
14 * Filtering Data: 
15         How to protect yourself from redial attacks
16
17 * Proper Device Naming: 
18         Why to not use numbered extensions for devices
19
20 * Secure Passwords: 
21         Secure passwords limit your risk to brute force attacks
22
23 * Reducing Pattern Match Typos: 
24         Using the 'same' prefix, or using Goto()
25
26 ----------------
27 Additional Links
28 ----------------
29
30 Additional links that contain useful information about best practices or
31 security are listed below.
32
33 * Seven Steps to Better SIP Security:
34         http://blogs.digium.com/2009/03/28/sip-security/
35
36 * Asterisk VoIP Security (webinar):
37         http://www.asterisk.org/security/webinar/
38
39
40 ==============
41 Filtering Data
42 ==============
43
44 In the Asterisk dialplan, several channel variables contain data potentially 
45 supplied by outside sources. This could lead to a potential security concern 
46 where those outside sources may send cleverly crafted strings of data which 
47 could be utilized, e.g. to place calls to unexpected locations.
48
49 An example of this can be found in the use of pattern matching and the ${EXTEN}
50 channel variable. Note that ${EXTEN} is not the only system created channel
51 variable, so it is important to be aware of where the data you're using is
52 coming from.
53
54 For example, this common dialplan takes 2 or more characters of data, starting 
55 with a number 0-9, and then accepts any additional information supplied by the
56 request.
57
58 [NOTE: We use SIP in this example, but is not limited to SIP only; protocols
59        such as Jabber/XMPP or IAX2 are also susceptible to the same sort of
60        injection problem.]
61        
62
63 [incoming]
64 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
65 exten => _X.,n,Dial(SIP/${EXTEN})
66 exten => _X.,n,Hangup()
67
68 This dialplan may be utilized to accept calls to extensions, which then dial a
69 numbered device name configured in one of the channel configuration files (such
70 as sip.conf, iax.conf, etc...) (see the section Proper Device Naming for more
71 information on why this approach is flawed).
72
73 The example we've given above looks harmless enough until you take into
74 consideration that several channel technologies accept characters that could
75 be utilized in a clever attack. For example, instead of just sending a request
76 to dial extension 500 (which in our example above would create the string
77 SIP/500 and is then used by the Dial() application to place a call), someone
78 could potentially send a string like "500&SIP/itsp/14165551212".
79
80 The string "500&SIP/itsp/14165551212" would then be contained within the 
81 ${EXTEN} channel variable, which is then utilized by the Dial() application in
82 our example, thereby giving you the dialplan line of:
83
84 exten => _X.,n,Dial(SIP/500&SIP/itsp/14165551212)
85
86 Our example above has now provided someone with a method to place calls out of
87 your ITSP in a place where you didn't expect to allow it. There are a couple of
88 ways in which you can mitigate this impact: stricter pattern matching, or using
89 the FILTER() dialplan function.
90
91 Strict Pattern Matching
92 -----------------------
93
94 The simple way to mitigate this problem is with a strict pattern match that does
95 not utilize the period (.) or bang (!) characters to match on one-or-more 
96 characters or zero-or-more characters (respectively). To fine tune our example
97 to only accept three digit extensions, we could change our pattern match to
98 be:
99
100 exten => _XXX,n,Dial(SIP/${EXTEN})
101
102 In this way, we have minimized our impact because we're not allowing anything
103 other than the numbers zero through nine. But in some cases we really do need to
104 handle variable pattern matches, such as when dialing international numbers
105 or when we want to handle something like a SIP URI. In this case, we'll need to
106 utilize the FILTER() dialplan function.
107
108 Using FILTER()
109 --------------
110
111 The FILTER() dialplan function is used to filter strings by only allowing
112 characters that you have specified. This is a perfect candidate for controlling
113 which characters you want to pass to the Dial() application, or any other
114 application which will contain dynamic information passed to Asterisk from an
115 external source. Lets take a look at how we can use FILTER() to control what
116 data we allow.
117
118 Using our previous example to accept any string length of 2 or more characters, 
119 starting with a number of zero through nine, we can use FILTER() to limit what 
120 we will accept to just numbers. Our example would then change to something like:
121
122 [incoming]
123 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
124 exten => _X.,n,Dial(SIP/${FILTER(0-9,${EXTEN})})
125 exten => _X.,n,Hangup()
126
127 Note how we've wrapped the ${EXTEN} channel variable with the FILTER() function
128 which will then only pass back characters that fit into the numerical range that
129 we've defined.
130
131 Alternatively, if we didn't want to utilize the FILTER() function within the
132 Dial() application directly, we could save the value to a channel variable,
133 which has a side effect of being usable in other locations of your dialplan if
134 necessary, and to handle error checking in a separate location.
135
136 [incoming]
137 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
138 exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
139 exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
140 exten => _X.,n,Hangup()
141
142 Now we can use the ${SAFE_EXTEN} channel variable anywhere throughout the rest
143 of our dialplan, knowing we've already filtered it. We could also perform an
144 error check to verify that what we've received in ${EXTEN} also matches the data
145 passed back by FILTER(), and to fail the call if things do not match.
146
147 [incoming]
148 exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
149 exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0-9,${EXTEN})})
150 exten => _X.,n,GotoIf($[${EXTEN} != ${SAFE_EXTEN}]?error,1)
151 exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
152 exten => _X.,n,Hangup()
153
154 exten => error,1,Verbose(2,Values of EXTEN and SAFE_EXTEN did not match.)
155 exten => error,n,Verbose(2,EXTEN: "${EXTEN}" -- SAFE_EXTEN: "${SAFE_EXTEN}")
156 exten => error,n,Playback(silence/1&invalid)
157 exten => error,n,Hangup()
158
159 Another example would be using FILTER() to control the characters we accept when
160 we're expecting to get a SIP URI for dialing.
161
162 [incoming]
163 exten => _[0-9a-zA-Z].,1,Verbose(2,Incoming call to extension ${EXTEN})
164 exten => _[0-9a-zA-Z].,n,Dial(SIP/${FILTER(.@0-9a-zA-Z,${EXTEN})
165 exten => _[0-9a-zA-Z].,n,Hangup()
166
167 Of course the FILTER() function doesn't check the formatting of the incoming
168 request. There is also the REGEX() dialplan function which can be used to
169 determine if the string passed to it matches the regular expression you've
170 created, and to take proper action on whether it matches or not. The creation of
171 regular expressions is left as an exercise for the reader.
172
173 More information about the FILTER() and REGEX() dialplan functions can be found
174 by typing "core show function FILTER" and "core show function REGEX" from your
175 Asterisk console.
176
177
178 ====================
179 Proper Device Naming
180 ====================
181
182 In Asterisk, the concept of an extension number being tied to a specific device
183 does not exist. Asterisk is aware of devices it can call or receive calls from,
184 and how you define in your dialplan how to reach those devices is up to you.
185
186 Because it has become common practice to think of a specific device as having an
187 extension number associated with it, it only becomes natural to think about
188 naming your devices the same as the extension number you're providing it. But
189 by doing this, you're limiting the powerful concept of separating user from
190 extensions, and extensions from devices.
191
192 It can also be a security hazard to name your devices with a number, as this can
193 open you up to brute force attacks. Many of the current exploits deal with
194 device configurations which utilize a number, and even worse, a password that
195 matches the devices name. For example, take a look at this poorly created device
196 in sip.conf:
197
198 [1000]
199 type=friend
200 context=international_dialing
201 secret=1000
202
203 As implied by the context, we've permitted a device named 1000 with a password
204 of 1000 to place calls internationally. If your PBX system is accessible via
205 the internet, then your system will be vulnerable to expensive international
206 calls. Even if your system is not accessible via the internet, people within
207 your organization could get access to dialing rules you'd prefer to reserve only
208 for certain people.
209
210 A more secure example for the device would be to use something like the MAC
211 address of the device, along with a strong password (see the section Secure
212 Passwords). The following example would be more secure:
213
214 [0004f2040001]
215 type=friend
216 context=international_dialing
217 secret=aE3%B8*$jk^G
218
219 Then in your dialplan, you would reference the device via the MAC address of the
220 device (or if using the softphone, a MAC address of a network interface on the
221 computer).
222
223 Also note that you should NOT use this password, as it will likely be one of the
224 first ones added to the dictionary for brute force attacks.
225
226
227 ================
228 Secure Passwords
229 ================
230
231 Secure passwords are necessary in many (if not all) environments, and Asterisk 
232 is certainly no exception, especially when it comes to expensive long distance
233 calls that could potentially cost your company hundreds or thousands of dollars
234 on an expensive monthly phone bill, with little to no recourse to fight the
235 charges.
236
237 Whenever you are positioned to add a password to your system, whether that is
238 for a device configuration, a database connection, or any other secure 
239 connection, be sure to use a secure password. A good example of a secure
240 password would be something like:
241
242 aE3%B8*$jk^G
243
244 Our password also contains 12 characters with a mixture of upper and
245 lower case characters, numbers, and symbols. Because these passwords are likely 
246 to only be entered once, or loaded via a configuration file, there is
247 no need to create simple passwords, even in testing. Some of the holes found in
248 production systems used for exploitations involve finding the one test extension
249 that contains a weak password that was forgotten prior to putting a system into
250 production.
251
252 Using a web search you can find several online password generators such as
253 http://www.strongpasswordgenerator.com or there are several scripts that can be
254 used to generate a strong password.
255
256
257 ============================
258 Reducing Pattern Match Typos
259 ============================
260
261 As of Asterisk 1.6.2, a new method for reducing the number of complex pattern
262 matches you need to enter, which can reduce typos in your dialplan, has been
263 implemented. Traditionally, a dialplan with a complex pattern match would look
264 something like:
265
266 exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
267 exten => _[3-5]XXX,n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
268 exten => _[3-5]XXX,n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
269 exten => _[3-5]XXX,n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
270 exten => _[3-5]XXX,n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
271 exten => _[3-5]XXX,n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
272 exten => _[3-5]XXX,n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
273 exten => _[3-5]XXX,n,Hangup()
274
275 exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
276 exten => error,n,Playback(silence/1&num-not-in-db)
277 exten => error,n,Hangup()
278
279 Of course there exists the possibility for a typo when retyping the pattern
280 match _[3-5]XXX which will match on extensions 3000 through 5999. We can
281 minimize this error by utilizing the same => prefix on all lines beyond the
282 first one. Our same dialplan with using same => would look like the following:
283
284 exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
285 same => n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
286 same => n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
287 same => n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
288 same => n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
289 same => n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
290 same => n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
291 same => n,Hangup()
292
293 exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
294 same => n,Playback(silence/1&num-not-in-db)
295 same => n,Hangup()