|By Jackson Moore||
|October 4, 2001 12:00 AM EDT||
To secure your Web-based application you must close all known holes in your hardware and software as well as those you inadvertently open in your application's code.
This article addresses possible holes in your ColdFusion code that result from explicitly trusting the data your code accepts from URL parameters, form fields, cookies, browser variables, databases, or other external data sources. You must take measures to ensure that data from these sources won't cause your application to display improperly, crash, permit a security breach, or allow unintended server-side operations to be performed.
Although the exploits described in this article aren't specific to ColdFusion and many have been around for years, we'll examine ColdFusion practices for protecting your application, including data validation, encryption, and data integrity.
Untrusted Data Sources
If you conceptualize your application as a black box, any data entering that box should be validated before being processed. For Web-based applications, common sources of input that should be validated include URL parameters, form fields, cookies, browser variables, and databases.
With URLs a user can simply add, change, or delete URL parameters in the query string. Form fields might not be as obvious, but it's a trivial exercise to save a form-based HTML page on your computer, change hidden form fields, or bypass client-side validation and resubmit the form.
Likewise, a cookie can be easily manipulated by using a text editor to make a few careful changes. CGI variables that originate in the browser ("cgi.http_referer") must also be treated as suspect since they can be spoofed or blocked.
Last, and maybe least considered, are the problems that can occur by not validating data retrieved from databases. Unless yours is the only database application, your application can't blindly trust the data in the database. What would happen if another application inserted a username containing a "<" character into the database?
These are the biggest sources of untrusted data, but you must audit your own situation carefully. Other sources of untrusted data are CFFILE, CFHTTP, COM objects, and any other means of accessing data outside the direct control of your application.
What Can Happen
Improper HTML Display
Perhaps the most benign of holes, allowing user input to affect the display of your page is not only unprofessional, but is a clue to serious hackers that little or no security precautions are in place.
If you have a search form that allows users to search your Web site, you might display a response to the user such as "Your search for 'ColdFusion' resulted in a gazillion matches." But what happens if your user searches for something like "</TD>" or "<B>" or simply a "<"? This may cause your page to display improperly - reformatting your text or omitting portions of your page altogether. Furthermore, some browsers are known to crash when parsing ill-formed HTML.
Improper display can also be caused when pulling data from a database that you don't exclusively control. A database of magazine articles may contain characters that cause display problems if you don't validate the data after you retrieve it from the database.
Bypassed Client-Side Validation
Since all client-side validation, by definition, takes place on the client, a user can bypass validation code and submit the form with nonvalidated data. Users could have scripting disabled in their browser or bypass the validation code manually after saving the form to their computer.
As mentioned, "cgi.http_referer" (or any other client-side variable) can't be relied upon to verify the origin of a form submission. "cgi.http_referer" can be spoofed to make you believe that the form was submitted from your site or blocked (by a firewall or privacy software), preventing valid users from submitting forms.
For this example let's assume you have a message board where users can read and post messages, and a user enters the following:
If you're not validating this text field, every user that views your message board will be "treated" to a new window that originates from and appears to be authorized by your site. Other potentially damaging HTML tags include <OBJECT> and <APPLET>.
Serious attackers will look for any in-formation about your server configuration that allows them to identify potential holes. Those unfriendly ColdFusion error messages (see Figure 1) that are so helpful when debugging an application are a gold mine to a hacker looking to have some fun.
As you can see from this figure, the user is presented with an error message revealing a physical path on the server.
The amount of critical information displayed will depend on the type of error, your ColdFusion server settings, server platform, and database server.
Even if you employ an authentication framework, you must still validate data received from the client to prevent unauthorized access to restricted areas of your Web site. Consider a situation where you design a Web site for a magazine that wants to restrict some of the articles to subscribers only.
- Case 1: <a href="display.cfm? article_ id=14">Cover Story</a>
- Case 2: <a href="articles/2001/july/ cover.htm">Cover Story</a>
Unintended Server Operations
Holes that allow unauthorized server-side operations to be performed are the most disastrous. Some databases, for example, support multiple SQL statements inside a CFQUERY. Building on the magazine example we might construct the following query:
<cfquery name="qArticles" datasource="testDB">
SELECT article_copy FROM articles
WHERE article_id = #url.article_id#
This works fine if the URLs submitted by the user have valid article numbers, but not URLs like this:
With Microsoft SQL Server (among others) this user just deleted every record in the "articles" table. Granted, the user must know the name of your table, but through the error messages mentioned earlier or simply guessing common table names, this isn't difficult.
You need to analyze your other server software for similar "features." For example, Allaire Security Bulletin ASB99-09 (www.allaire.com/handlers/index.cfm?id=11069&method=full) warns of an issue with Microsoft Access that allows users to append VBA commands to a SQL string.
Any server software your application interfaces with that supports scripting needs to be audited for related patches. If you validate all user input, however, you're likely to avoid these vulnerabilities.
What You Can Do
ColdFusion includes two built-in methods for validating data received from form data: server-side validation using hidden <INPUT> tags and client-side validation using CFINPUT. Both methods are designed for validating form data, but, as you know, form data is just one of the many untrusted data sources you must contend with.
That said, these techniques are useful in some cases and provide built-in validation for required fields, data types such as integer and date, as well as data values such as credit card and social security numbers. The online help provides documentation and examples for each method.
Use Server-Side Validation
Furthermore, client-side validation can't perform some data validation such as preventing duplicate database records or testing uploaded files. The advantage to client-side scripting is that it provides immediate feedback to the user without a round-trip to the server for validation.
<cfinput type="text" name="firstname" required="yes">
If you don't manually scope your variables, ColdFusion looks for them in various scopes in the following order: local variables, CGI, file, URL, form, cookie, and client variables. If you don't scope variables in your code, you won't know whether they're coming from the URL, a form, or a cookie. Scoping your variables will also make your code easier to follow and give you a slight performance boost.
To prevent the display of error messages that may reveal information about your server configuration, use structured error handling (with CFTRY/CFCATCH blocks) and/or site-wide error handlers (CFERROR). This will allow you to trap any errors and continue processing your page accordingly.
Disabling the "Display the template path in error messages" setting in the ColdFusion Administrator will prevent physical paths from being displayed in most, but not all (see Figure 1), error messages that do get through to the user.
For more information on handling errors look through your back issues of CFDJ for the "Toward Better Error Handling" series (Vol. 2, issues 10 and 12, and Vol. 3, issue 2) by Charles Arehart. These are good articles that will help even beginners get up to speed on error handling.
Data Type Validation
Perhaps the single most important validation to perform is to verify the data type of suspicious data - making sure, for example, that a variable that's supposed to be a number is actually a number. This ensures that all subsequent processing of this type of data won't throw an error by performing a date operation on a nondate value or by trying to insert a nonnumeric value into a numeric database column.
Two useful tags for this purpose are CFPARAM and CFQUERYPARAM. With CFPARAM, specify the "type" attribute with any of the following data types: array, binary, boolean, date, numeric, query, string, struct, or uuid.
<cfparam name="url.myValue" type="numeric">
If the value of "url.myValue" is anything other than numeric, ColdFusion will throw an error. Using this in a meaningful way will require the use of CFTRY/CFCATCH blocks to catch the error and handle it properly.
CFQUERYPARAM tags are nested within CFQUERY tags and will give you some control over data validation. Refer to the ColdFusion documentation for CFQUERYPARAM for a list of SQL data types that can be validated. Again, ColdFusion throws an error if the validation fails.
ColdFusion also has several built-in functions (IsDate(), IsNumeric(), etc.) that allow you to determine data types without using error handling. If you need more specific data-type validations (such as integer or hexadecimal), you'll have to write your own validation code.
Another helpful ColdFusion function for validating numeric data types is Val(). Val() will return a number from the beginning of a string or 0 if the string can't be converted to a number. This function is particularly handy when dealing with a peculiar aspect of ColdFusion's support for scientific notation.
ColdFusion treats the value "1D2" the same as "1E2" - both are scientific notations for "100". ColdFusion considers both values to be valid numeric values, but your database probably won't even if it supports scientific notation. Using the Val() function will ensure that the value is converted to the more recognized scientific notation format:
#val("1d2")# <!--- 100 --->
#val("1d13")# <!--- 1E+013 --->
For example, if your user enters his or her age into a form as "3D1" (30), you want to make sure that inserting this value into your database won't cause an error even though this is a valid number in ColdFusion.
Data Value Validation
While data-type validation should prevent errors in subsequent ColdFusion code, it doesn't ensure that the value of the data is acceptable. Consider again our example of the magazine Web site. Some articles are available to the general public, while others are available only to subscribers.
If the user manually changes "article_id" to a different (but valid) integer, should the user be presented with the article carte blanche? In this example the answer is no. For each article the user requests, we must authenticate and verify that he or she is allowed to view the requested article. You can't assume that users won't try to guess new paths or values for URL parameters, form fields, or cookies in order to access restricted portions of your Web site.
Another case where data value validation is critical is when the range of legal data values for a data type in ColdFusion differs from your database. ColdFusion, for example, considers dates as large as December 31, 9999, as valid dates. In SQL Server 7, the "datetime" data type will accept this value, but the "smalldatetime" data type won't. To prevent database errors with date data types, you need to ensure that the date value is within an acceptable range for your database column.
There are many other reasons why you need to validate the value of a piece of data, not just its data type. Preventing duplicate records in a database or making sure the length of a string value is within acceptable minimum and maximum lengths are additional examples of when the value of the data must be validated. The bottom line is that (just like data types) you can't make any assumptions about the value of data received from a client.
Defining Character Sets
Validating string data presents its own set of unique challenges since there are many special characters reserved by ColdFusion, URLs, HTML, and database software. Because ColdFusion doesn't have any built-in validation functionality like Perl's taint-checking mechanism, it's the developer's responsibility to perform all necessary string validations.
In nearly all cases you'll protect yourself better by first defining which characters to allow and then making sure that the suspect string contains only those characters. This is preferable to defining which characters are illegal (though this may seem easier to implement), because it's very easy to forget one and it reduces your vulnerability to (as yet) unknown exploits.
As an example, let's consider a form field that accepts a username field and requires all usernames to contain only letters. It's safer to verify that only letters are submitted as opposed to checking for all possible illegal characters. You can use a regular expression to verify that no other character is allowed:
<cfif refindnocase("[^a-z]",form.username) neq 0>
<!--- invalid username --->
The validation becomes more complicated for string data that has to be more flexible. Our example of the cross-site scripting exploit was due to a developer allowing <SCRIPT> tags in message board posts. This particular example could have been avoided by defining a character set that excluded the "<" and ">" characters. But what if you want to allow users to use <B>, <I>, and <U> for formatting purposes within their message post? Now you have to allow some tags but not others.
As with defining single character sets, you're far safer determining which HTML tags to allow as opposed to identifying the tags that may potentially cause problems. I take issue with some of the available custom tags that focus on which HTML tags to disallow because future additions to the HTML specification or browser-specific tags may require you to revisit your code.
If you want to allow bold, italic, and underline formatting in your message posts, allow only those and disallow all others. The following code will remove all tags except for <B></B>, <I></I>, and <U></U>:
This, of course, won't validate the HTML to ensure it's well formed. Limiting the allowable HTML tags will minimize the amount of validation needed since you don't want to have errors caused by a user who failed to provide an end tag or improperly nested certain tags. If the user leaves out a "</B>" tag, you won't have a problem if the message post is encapsulated in a table cell. However, a misplaced <DIV> or </TD> can really wreak havoc on the display of your page or crash the browser.
Another approach is to encrypt the data that appears in URLs, form fields, and cookies. Consider the earlier example of the magazine Web site: if we encrypt "article_id" our link might look like:
The new value of "article_id" makes it less obvious to the user how "article_id" is used. Curious users may still tamper with the value, but after failing once or twice will give up.
ColdFusion offers two complementary functions, Encrypt() and Decrypt(), to perform encryption. They both take a string to encrypt as well as a key to use in the encryption process.
Encrypt()'s XOR-based encryption, though useful, is weak compared to encryption methods (such as that used in 128-bit SSL) considered secure by today's standards. Encrypt() shouldn't be used for sensitive information (credit card numbers or medical information), but it can be used to prevent most attempts to casually change "nonsensitive" values in URLs, form fields, and cookies.
Strings encrypted with Encrypt() can contain many potentially damaging characters (new lines, form feeds, backspaces, greater-than signs, carriage returns, etc.):
encrypt("Macromedia","key") = *=(IX [email protected]%$V#\!
The last character (which you can't see) is a new line character. Practical use of the Encrypt() function will generally require another encoding step such as URLEncodedFormat() to escape all illegal characters in the string. Your decryption process then becomes a two-step process as well - decode and decrypt.
Another drawback to the Encrypt() function is that there's no data integrity check to ensure that the encrypted string hasn't been tampered with. Using the above example I decrypted the encrypted string, but changed the number 5 to 2:
decrypt("*=(IX [email protected]%$V#\! ","key") = Macromydia
As you can see, the decrypted string was successfully decrypted but resulted in a value different from the original.
At the risk of losing some objectivity, I'll mention a tag I wrote called CF_CRYP (available from the Developers Exchange, http://devex.allaire.com/developer/gallery/). CF_CRYP builds on the default encryption of the Encrypt() function, but encodes the resulting string and adds a checksum.
The result is an encrypted string containing only numbers and letters with a checksum. Changing a single character in a CF_CRYP-encrypted string can be detected because the checksum of the decrypted value won't match the checksum of the original unencrypted value. CF_CRYP also provides a return structure with error information so you can detect tampering and, potentially, block that user from further access.
Using CF_CRYP to encrypt a value of "14" with a key of "somekey" produces "0101J442509E78541". To access the subscriber-only articles, the user would have to know the encoding scheme, key, and recalculate the checksum. This is a good solution for this example because if the encryption scheme was broken, the worst that can happen is an unauthorized user views some subscriber-only articles. If this happens, you should probably give the user a free subscription to your magazine anyway!
CFCONTENT will allow you to place content outside of your Web root directory and still send the content to a user. This is preferable when the files (PDF documents, video clips, etc.) require some type of user authentication to access. Since these files exist on your server outside of the Web root, users can't access the file with any URL. To view the file they have to access a page where you should authenticate them and use CFCONTENT to deliver the file.
Since many of the most damaging server-side operations are unauthorized database operations, your database authentication framework should be audited. Carefully review the operations that users need to be able to perform and then limit the SQL operations that can be performed under that user account. Generally speaking, regular users should be restricted to SELECT statements and, in some cases, UPDATE and INSERT.
Even if a user manages to get multiple commands through to your server, only those operations authorized for this user would be allowed. You must combine this type of security with the other guidelines in this article since even a benign SELECT operation can allow a user to view unauthorized content. If you use other server-side applications (including COM objects), take advantage of any built-in user authentication.
Most databases will also allow you to perform data validation at the database level. This is a good solution when you have numerous applications inserting data into a database. By moving some data validation to the database, you can remove redundant validation routines from each application.
Most users are honest people using your application for the purpose it was designed for. However, a small group of users (some armed with homegrown HTTP clients) will attempt to exploit any holes that exist in your code. Form fields, cookies, and browser variables are just as likely as URL parameters (maybe more so since they're less obvious to inexperienced developers) to contain hack attempts.
Taken together, the techniques presented in this article will help you protect your application from any malicious data sent by a user. Whether the data is tampered with accidentally or on purpose, it's your job as the developer to close these code-level holes.
- "Security Best Practice: Validating Browser Input": www.allaire.com/handlers/index.cfm?id=14558&method=full
- "Cross-Site Scripting Vulnerability Information": www.allaire.com/handlers/index.cfm?id=14557&method=full
- "Multiple SQL Statements in Dynamic Queries":www.allaire.com/handlers/index.cfm?id=8728&method=full
- "Understanding Malicious Content Mitigation for Web Developers": www. cert.org/tech_tips/malicious_code_mitigation.html
Fact is, enterprises have significant legacy voice infrastructure that’s costly to replace with pure IP solutions. How can we bring this analog infrastructure into our shiny new cloud applications? There are proven methods to bind both legacy voice applications and traditional PSTN audio into cloud-based applications and services at a carrier scale. Some of the most successful implementations leverage WebRTC, WebSockets, SIP and other open source technologies. In his session at @ThingsExpo, Da...
Sep. 25, 2016 04:45 AM EDT Reads: 1,486
Technology vendors and analysts are eager to paint a rosy picture of how wonderful IoT is and why your deployment will be great with the use of their products and services. While it is easy to showcase successful IoT solutions, identifying IoT systems that missed the mark or failed can often provide more in the way of key lessons learned. In his session at @ThingsExpo, Peter Vanderminden, Principal Industry Analyst for IoT & Digital Supply Chain to Flatiron Strategies, will focus on how IoT de...
Sep. 25, 2016 04:15 AM EDT Reads: 943
SYS-CON Events announced today that China Unicom will exhibit at the 19th International Cloud Expo, which will take place on November 1–3, 2016, at the Santa Clara Convention Center in Santa Clara, CA. China United Network Communications Group Co. Ltd ("China Unicom") was officially established in 2009 on the basis of the merger of former China Netcom and former China Unicom. China Unicom mainly operates a full range of telecommunications services including mobile broadband (GSM, WCDMA, LTE F...
Sep. 25, 2016 04:15 AM EDT Reads: 1,677
SYS-CON Events announced today that Roundee / LinearHub will exhibit at the WebRTC Summit at @ThingsExpo, which will take place on November 1–3, 2016, at the Santa Clara Convention Center in Santa Clara, CA. LinearHub provides Roundee Service, a smart platform for enterprise video conferencing with enhanced features such as automatic recording and transcription service. Slack users can integrate Roundee to their team via Slack’s App Directory, and '/roundee' command lets your video conference ...
Sep. 25, 2016 04:15 AM EDT Reads: 1,378
DevOps at Cloud Expo, taking place Nov 1-3, 2016, at the Santa Clara Convention Center in Santa Clara, CA, is co-located with 19th Cloud Expo and will feature technical sessions from a rock star conference faculty and the leading industry players in the world. The widespread success of cloud computing is driving the DevOps revolution in enterprise IT. Now as never before, development teams must communicate and collaborate in a dynamic, 24/7/365 environment. There is no time to wait for long dev...
Sep. 25, 2016 03:15 AM EDT Reads: 3,341
Almost two-thirds of companies either have or soon will have IoT as the backbone of their business in 2016. However, IoT is far more complex than most firms expected. How can you not get trapped in the pitfalls? In his session at @ThingsExpo, Tony Shan, a renowned visionary and thought leader, will introduce a holistic method of IoTification, which is the process of IoTifying the existing technology and business models to adopt and leverage IoT. He will drill down to the components in this fra...
Sep. 25, 2016 03:00 AM EDT Reads: 1,444
There is growing need for data-driven applications and the need for digital platforms to build these apps. In his session at 19th Cloud Expo, Muddu Sudhakar, VP and GM of Security & IoT at Splunk, will cover different PaaS solutions and Big Data platforms that are available to build applications. In addition, AI and machine learning are creating new requirements that developers need in the building of next-gen apps. The next-generation digital platforms have some of the past platform needs a...
Sep. 25, 2016 02:45 AM EDT Reads: 1,696
I'm a lonely sensor. I spend all day telling the world how I'm feeling, but none of the other sensors seem to care. I want to be connected. I want to build relationships with other sensors to be more useful for my human. I want my human to understand that when my friends next door are too hot for a while, I'll soon be flaming. And when all my friends go outside without me, I may be left behind. Don't just log my data; use the relationship graph. In his session at @ThingsExpo, Ryan Boyd, Engi...
Sep. 25, 2016 02:15 AM EDT Reads: 1,204
SYS-CON Events announced today that Numerex Corp, a leading provider of managed enterprise solutions enabling the Internet of Things (IoT), will exhibit at the 19th International Cloud Expo | @ThingsExpo, which will take place on November 1–3, 2016, at the Santa Clara Convention Center in Santa Clara, CA. Numerex Corp. (NASDAQ:NMRX) is a leading provider of managed enterprise solutions enabling the Internet of Things (IoT). The Company's solutions produce new revenue streams or create operating...
Sep. 25, 2016 12:45 AM EDT Reads: 1,928
Information technology is an industry that has always experienced change, and the dramatic change sweeping across the industry today could not be truthfully described as the first time we've seen such widespread change impacting customer investments. However, the rate of the change, and the potential outcomes from today's digital transformation has the distinct potential to separate the industry into two camps: Organizations that see the change coming, embrace it, and successful leverage it; and...
Sep. 25, 2016 12:45 AM EDT Reads: 1,033
Data is an unusual currency; it is not restricted by the same transactional limitations as money or people. In fact, the more that you leverage your data across multiple business use cases, the more valuable it becomes to the organization. And the same can be said about the organization’s analytics. In his session at 19th Cloud Expo, Bill Schmarzo, CTO for the Big Data Practice at EMC, will introduce a methodology for capturing, enriching and sharing data (and analytics) across the organizati...
Sep. 24, 2016 09:45 PM EDT Reads: 1,606
The vision of a connected smart home is becoming reality with the application of integrated wireless technologies in devices and appliances. The use of standardized and TCP/IP networked wireless technologies in line-powered and battery operated sensors and controls has led to the adoption of radios in the 2.4GHz band, including Wi-Fi, BT/BLE and 802.15.4 applied ZigBee and Thread. This is driving the need for robust wireless coexistence for multiple radios to ensure throughput performance and th...
Sep. 24, 2016 08:30 PM EDT Reads: 1,444
The Internet of Things can drive efficiency for airlines and airports. In their session at @ThingsExpo, Shyam Varan Nath, Principal Architect with GE, and Sudip Majumder, senior director of development at Oracle, will discuss the technical details of the connected airline baggage and related social media solutions. These IoT applications will enhance travelers' journey experience and drive efficiency for the airlines and the airports. The session will include a working demo and a technical d...
Sep. 24, 2016 08:00 PM EDT Reads: 1,654
SYS-CON Events announced today the Enterprise IoT Bootcamp, being held November 1-2, 2016, in conjunction with 19th Cloud Expo | @ThingsExpo at the Santa Clara Convention Center in Santa Clara, CA. Combined with real-world scenarios and use cases, the Enterprise IoT Bootcamp is not just based on presentations but with hands-on demos and detailed walkthroughs. We will introduce you to a variety of real world use cases prototyped using Arduino, Raspberry Pi, BeagleBone, Spark, and Intel Edison. Y...
Sep. 24, 2016 07:00 PM EDT Reads: 2,792
If you’re responsible for an application that depends on the data or functionality of various IoT endpoints – either sensors or devices – your brand reputation depends on the security, reliability, and compliance of its many integrated parts. If your application fails to deliver the expected business results, your customers and partners won't care if that failure stems from the code you developed or from a component that you integrated. What can you do to ensure that the endpoints work as expect...
Sep. 24, 2016 04:30 PM EDT Reads: 1,514
Enterprise IT has been in the era of Hybrid Cloud for some time now. But it seems most conversations about Hybrid are focused on integrating AWS, Microsoft Azure, or Google ECM into existing on-premises systems. Where is all the Private Cloud? What do technology providers need to do to make their offerings more compelling? How should enterprise IT executives and buyers define their focus, needs, and roadmap, and communicate that clearly to the providers?
Sep. 24, 2016 01:00 PM EDT Reads: 1,490
The Transparent Cloud-computing Consortium (abbreviation: T-Cloud Consortium) will conduct research activities into changes in the computing model as a result of collaboration between "device" and "cloud" and the creation of new value and markets through organic data processing High speed and high quality networks, and dramatic improvements in computer processing capabilities, have greatly changed the nature of applications and made the storing and processing of data on the network commonplace.
Sep. 24, 2016 12:00 PM EDT Reads: 775
SYS-CON Events announced today that SoftLayer, an IBM Company, has been named “Gold Sponsor” of SYS-CON's 18th Cloud Expo, which will take place on June 7-9, 2016, at the Javits Center in New York, New York. SoftLayer, an IBM Company, provides cloud infrastructure as a service from a growing number of data centers and network points of presence around the world. SoftLayer’s customers range from Web startups to global enterprises.
Sep. 24, 2016 12:00 PM EDT Reads: 781
Digital innovation is the next big wave of business transformation based on digital technologies of which IoT and Big Data are key components, For example: Business boundary innovation is a challenge to excavate third-party business value using IoT and BigData, like Nest Business structure innovation may propose re-building business structure from scratch, as Uber does in the taxicab industry The social model innovation is also a big challenge to the new social architecture with the design fr...
Sep. 24, 2016 11:45 AM EDT Reads: 1,045
SYS-CON Events announced today that Pulzze Systems will exhibit at the 19th International Cloud Expo, which will take place on November 1–3, 2016, at the Santa Clara Convention Center in Santa Clara, CA. Pulzze Systems, Inc. provides infrastructure products for the Internet of Things to enable any connected device and system to carry out matched operations without programming. For more information, visit http://www.pulzzesystems.com.
Sep. 24, 2016 10:45 AM EDT Reads: 1,726