The CERT Perl Secure Coding Standard

Secure Coding Add comments

David Svoboda
Software Security Engineer
CERT Secure Coding Initiative

David Svoboda As security specialists, we are often asked to audit software and provide expertise on secure coding practices. Our research and efforts have produced several coding standards specifically dealing with security in popular programming languages, such as C, Java, and C++. This posting describes our work on the CERT Perl Secure Coding Standard, which provides a core of well-documented and enforceable coding rules and recommendations for Perl, which is a popular scripting language.

Perl is a relatively young language, only slightly older than Java. Perl became popular early in its lifetime because it was the first general-purpose scripting language on many Unix platforms. Perl enjoyed a second burst of popularity as the web became prominent because it was especially well-suited to writing Common Gateway Interface (CGI) scripts.

In recent years Perl's popularity has been cemented by CPAN, a public repository of free software libraries written in Perl. Any computer with Perl installed provides straightforward mechanisms to install and use any software library from CPAN. This feature enables programmers to use libraries provided by the community easily and quickly. Several new features in Perl began life as CPAN modules before being integrated into the language. As a result of its popularity, many important software systems are written in Perl, such as the Request  Tracker database (RT), an open-source project for managing tickets or bugs for a help desk, which is maintained by Best Practical Solutions. Many websites, such as amazon.com, also rely on Perl code on their servers.

The CERT Perl Secure Coding standard is still young and growing. The C and Java standards have more than 200 rules in about 20 sections each. The Perl standard currently has slightly more than 30 rules in the following eight sections:

  1. Input Validation and Data Sanitization  – issues dealing with data provided by an attacker, such as XML injection and cross-site scripting (XSS).
  2. Declarations and Initialization – issues dealing with securely declaring variables and functions including package versus lexical variables, name clashes, and dangers of uninitialized data.
  3. Expressions  – issues dealing with Perl’s expressions syntax including list versus scalar contexts, when to use the $_ variable, and when to use the various types of comparison operators.
  4. Integers  – issues dealing with numbers, such as how to specify octal numbers.
  5. Strings  – issues dealing with strings and regular expressions (regexes) including the danger of providing a string literal to a subroutine that expects a regex.
  6. Object-Oriented Programming (OOP) – issues dealing with OOP are covered in this section, such as recognizing the convention of private variables.
  7. File Input and Output – issues dealing with how to safely work with files, including safely working with Perl’s filehandles.
  8. Miscellaneous – issues that don’t fall into other sections, such as handling dead code and unused variables.

Addressing Security Vulnerabilities in Perl

The Perl community has always prioritized practicality over theoretical elegance, and so it has always been considered an easy language to write code in—although Perl code is often considered ugly due to the tendency of some Perl developers to create “write only” programs. Perl was not designed as a secure programming language. However, problems relating to security in Perl programs have been discussed in security circles, and appear in databases such as the CERT vulnerability database. Moreover, companies that request software audits are just as likely to want Perl software audited as they are to request audits for C, C++, or Java. While the Perl community is interested in improving the language, the focus on security has historically tended to take a back seat to other priorities, such as new features and improved performance.

Our work on the CERT Perl Secure Coding Standard therefore centers on addressing issues in the Perl language and libraries that deal specifically with security. The standard covers issues, such as XML injection, integer security, and proper input and output, as outlined above. By making the standard publicly accessible, we invite the Perl community to help us improve the standard.

The standard leverages several sources to provide relevant material on security. For example, it takes advantage of the US-CERT vulnerability database, which contains entries on several vulnerabilities that address the Perl language or applications written in Perl. It also leverages experience gained from the Source Code Analysis Lab (SCALe), which has been used to perform security audits on several pieces of Perl code, including the previously-mentioned RequestTracker (RT) tool created by Best Practical Solutions. Other analysis tools, such as Perl::Critic, provide an automated audit of a Perl program by examining a codebase and producing a list of diagnostics. These diagnostics can range from insecure coding practices and bugs to stylistic issues. The SCALe project uses these tools to harvest the diagnostics that address security issues, while discarding diagnostics not relevant to security.

The CERT Perl standard can leverage the other CERT standards for security issues that are not bound to any particular language. For instance, many issues about securely opening files on a Unix machine are language-independent.  As a result, these portions of CERT standards for security issues can affect any software that runs on Unix systems regardless of the language in which it is written.

While Perl has many of the same security issues that plague C and Java, several issues are unique to Perl. For example, Perl's open() function can take two arguments, with the latter argument being either a file name or a shell command. The open() function either opens the file or executes the command. If the argument begins or ends with a | (pipe) character, it is interpreted as a command to execute. Consequently, if an attacker can specify a filename to Perl's open() function—and that filename begins or ends with |—the attacker can cause Perl to execute the command for which the file is named. This issue is discussed further in rule IDS31-PL in the CERT Perl Secure Coding Standard.

Perl has some technology that appears similar to other languages but presents unique problems when examined more closely. For example, C, Java, and Perl all share the concept of an array, which is a continuous vector of items that can be accessed via an index. In C and Java, arrays are fixed-size, which means they are created to hold a specific number of elements and their size remains fixed until they are destroyed. Trying to refer to an element greater than the size of the array is illegal. For example, asking for the 11th element in a 10-element array in Java will cause an exception to be thrown, which usually causes the program to crash.

In contrast, Perl's arrays can grow over their lifetime. Assigning a value to the 11th element of a 10-element Perl array causes the array to grow in memory such that the array contains 11 elements, so the request becomes valid. This quality makes Perl an especially agreeable language to work with Ibecause it never reports that an array is too small. If you were to assign a value to the 1,000,000,000th element of an array,however, Perl would attempt to grow the array enough to accommodate the request and might exhaust memory.

Exhausting system memory, whether deliberate or unintentional, can lead to security vulnerabilities because a system with limited memory will refuse to provide memory to any program that requests more. At the same time, many programs fail to check whether their memory requests succeeded. A machine with no free memory, therefore, is likely to have running programs that crash, either unintentionally or by design, using some sort of “out of memory” error. Consequently, the CERT Perl Secure Coding standard contains rule IDS32-PL, which forbids allowing untrusted users from providing an array index, lest they cause Perl to exhaust memory with an excessively large number.

What’s Ahead for the CERT Perl Secure Coding Standard

We are adding several rules each week, and presumably the Perl secure coding standard can grow to about the same size as the C or Java standards since it’s comparable in scope. We welcome your assistance in helping us complete the standard.

Editor's Note: In response to feedback from our readers, this post has been edited. The post originally stated "Asking for the 11th element of a 10-element Perl array causes the array to grow in memory such that the array contains 11 elements, so the request becomes valid." As our readers pointed out in the comments section, "Simple asking is not enough." The post now states that "Assigning a value to the 11th element of a 10-element Perl array causes the array to grow in memory such that the array contains 11 elements, so the request becomes valid."

Additional Resources

The CERT Perl Secure Coding Standard may be viewed at
https://www.securecoding.cert.org/confluence/display/perl/CERT+Perl+Secure+Coding+Standard

Share this

Share on Facebook Send to your Twitter page  Save to del.ico.us  Save to LinkedIn  Digg this  Stumble this page.  Save this page on your Google Home Page 

21 responses to “The CERT Perl Secure Coding Standard”

  1. Alun Jones Says:
    I would really like to see this as a single document that can be downloaded, printed and/or perused at leisure offline. Is it possible to do that?
  2. John Souvestre Says:
    Likewise, I would like to be able to download it as a single document also. Thanks.
  3. Dave Page Says:
    Strange that there isn't a mention in the input parsing section of Perl's "taint" mode, which automatically treats user input etc. as untrusted and will refuse to pass it to the shell etc. See "perldoc perlsec" for more details.
  4. Peter Makholm Says:
    Perl::Critic can not be recommended to much. It is a must know when reviewing Perl code.

    Is there any of you coding recommendations where the non-compliant form isn't found by tests included in the standard Perl::Critic suite?

    At least the use of two args open mentioned in the article is handled by analysing your code with Perl::Critic.

    But while discussing the Perl community's commitment to security related issues withing the language implementation I think you ought to notice the issue related to hash randomization fixed by Perl years before being noticed by other language communities.
  5. David Svoboda Says:
    Re: single document:

    The CERT Perl Secure Coding Standard is another entry in CERT's current lineup of secure coding standards. Several of our coding standards have been published as books by Addison-Wesley:

    The CERT C Secure Coding Standard
    http://www.informit.com/store/product.aspx?isbn=0321563212
    The CERT Oracle Secure Coding Standard for Java
    http://www.informit.com/store/product.aspx?isbn=0321803957

    The Perl coding standard may also be published one day. Consequently, our publisher would require that the material not be easily downloadable as one single document. So we cannot provide a single-document version is not possible. We apologize for the inconvenience.
  6. David Svoboda Says:
    Re: taint mode: That's a good point. AFAICT Perl's taint mode is an old feature (I believe Perl 4 had it), and has no built-in analogues in Python or Ruby. It certainly deserves mention in the CERT Perl Secure Coding Standard. At this point, we must conduct more research on the security of taint mode before we can provide definitive advice. At a quick glance, it seems to provide a good framework for preventing various injections. It is clearly not perfect (since that is theoretically impossibile), and because of its imperfections, you can easily obtain a false sense of security.

    I'll try to get to it this week, and add a few rules specifically dealing with taint mode.
  7. David Svoboda Says:
    Re: Perl::Critic: We have found Perl::Critic very useful in conducting security audits of Perl source code. Due to its usefulness, many of our early rules were based on checkers already implemented in Perl::Critic. But we have recently started adding rules that aren't checked by Perl::Critic (yet!) Here are a few:

    DCL06-PL. Do not name a subroutine after a builtin function
    https://www.securecoding.cert.org/confluence/display/perl/DCL06-PL.+Do+not+name+a+subroutine+after+a+builtin+function
    IDS35-PL. Do not invoke the eval() builtin with a string argument
    https://www.securecoding.cert.org/confluence/display/perl/IDS35-PL.+Do+not+invoke+the+eval%28%29+builtin+with+a+string+argument

    Re: hash randomization: Do you have a link or source for this issue? It may be worth noting, especially if there is advice we can give to Perl programmers today.
  8. Karen Etheridge Says:
    "In contrast, Perl's arrays can grow over their lifetime. Asking for the 11th element of a 10-element Perl array causes the array to grow in memory such that the array contains 11 elements, so the request becomes valid." I do not believe this is true. Do you have some code that demonstrates this behaviour?

    Is there a mailing list that I can join to discuss these standards, or to see updates as they are written?
  9. Peter Makholm Says:
    Re: DCL06-PL - This seems to be covered by the Subroutines::ProhibitBuiltinHomonyms policy. This is kind of tricky though as it might make perfectly sense to create methods with the same name as builtin functions. It is even needed when creating classes conforming to some standard interfaces. An good example is to provide an object that looks like an IO::Handle.

    Re: IDS35-PL - This would be BuiltinFunctions::ProhibitStringyEval which can even be configured to allow some cases where stringy eval is required. Of course there are other cases where stringy eval is well used, for example for dynamicaly generated code.

    Both rules show that the rules should not be enforced too strict. Using Perl::Critic might serve as an initial guideline picking places to start a review. But a too blind trust in Perl::Critic always being right is wrong.

    Re: Hash randomization. It is described in the perlsec manual page under the heading "Algorithmic Complexity Attacks". The individual programer does not need to do anything. The developers of the Perl language has taken the necessary steps to prevent some of these attacks.
  10. Peter Makholm Says:
    BTW: For more information on the hash reordering issue in other programming languages see http://www.kb.cert.org/vuls/id/903934 which includes a non-exhaustive list of products including this possible DoS.

    The 2003 paper referred to at the above page includes an analysis of the issue in Perl from that time.
  11. Robert C. Seacord Says:
    Alun,

    Once we have a completed and consistent standard we will publish as a single document, possibly with Addison-Wesley (our publishing partner).

    Thanks,
    rCs
  12. David Svoboda Says:
    OK, it seems that DCL06-PL was actually subsumed by DCL31-PL, which mentions Subroutines::ProhibitBuiltinHomonyms. So I've merged the two into DCL31-PL.

    You're right that BuiltinFunctions::ProhibitStringyEval does seem to check for IDS35-PL. I now remember complaining about this in one of my audits, and got some pushback, but don't remember details. Anyway, I've updated IDS35-PL to reference this checker.

    Here's more rules with no Perl::Critic checker. (Perhaps they are more appropriate for taint mode.)

    IDS34-PL. Do not pass untrusted, unsanitized data to a command interpreter
    https://www.securecoding.cert.org/confluence/display/perl/IDS34-PL.+Do+not+pass+untrusted%2C+unsanitized+data+to+a+command+interpreter
    IDS33-PL. Sanitize untrusted data passed across a trust boundary
    https://www.securecoding.cert.org/confluence/display/perl/IDS33-PL.+Sanitize+untrusted+data+passed+across+a+trust+boundary

    Re: hash randomization:
    Ah, so that's why the CERT vul didn't come up in any of our searches. It doesn't merit a rule by itself, as you note that developers don't need to do anything. Probably it deserves mention in a "Use the latest version of Perl" recommendation. We like showcasing real-world vulnerabilities, even if they are 'obsolete'. And especially if they involve entries from the US-CERT vulnerability database! :)
  13. David Svoboda Says:
    Re: arrays. This behavior is explained in rule    IDS32-PL. Validate any integer that is used as an array index    https://www.securecoding.cert.org/confluence/x/U4AIBQ

    The rule begins with a code sample that demonstrates an array growing. I've added a few print statements to that rule to show the growth of the array.

    Re: mailing list Every rule has a 'Comments' section at the bottom (much like this blog post). We encourage you to post rule-specific comments under the appropriate rule. You will need to create a user account to do this, but it's free.

    The CERT Perl Secure Coding Standard also has a 'Dashboard' page that shows the latest changes made to the standard. You can use it to view new rules, edits to existing rules, and new comments. It's what we use to provide quick feedback. It is available here:    https://www.securecoding.cert.org/confluence/dashboard.action

    Every page also has a 'Watch' option under the Tools menu. If you turn this option on, you'll get an email notification every time the page changes, or someone adds a comment.
  14. Peter Makholm Says:
    Re IDS34-PL...

    My preferred solution would be to use the more-than-three arguments form of open(). This way open() will bypass using the system shell to interprete the command:

    open( my $listing, "-|", "ls", "-F", $dir ) or croak("error executing command: $!");

    This is equivalent to the argument processing for system() which might be a bit better documented. This would work for your VU#583020 examples:

    system( "xmms", "-$command" );

    (BTW: these examples are not compliant with the recommendations of DCL06-PL. You might want to call the function do_play or something).

    But when it is possible to restate the problem to not cross a trust boundary as in your "Avoid interpreters" solution this is fine to. But it only works for the simple commands which are feasible to reimplement directly in your own code.

    In general I applaud your work for raising awareness about secure practices for Perl development. You write that you "invite the Perl community to help us improve the standard". Do you have any plans to make participation easier, for example by allowing comments directly along the recommendations?


    Regarding the point about hash randomization, the main point was top argue that the Perl language developers really do care about security and not just ignore it as the article might be read to imply. On the other hand, features does not just get deprecated and removed just because new easier to use features are introduced.

    But in many cases the same features that enables lousy programmers to introduce security problems are needed to solve other classes of problems. For example using stringy eval for run time generated code.
  15. David Svoboda Says:
    My previous post (#13) now explains how to leave comments about individual rules. So I'll post your specific technical issues to those rules & respond to the comments there.

    I did not mean to imply that the Perl community has ignored security. That would be absurd, as the community has been forced to improve its security simply because Perl was, initially, the best language for Web programming (and is still popular), so it was (and still is) a common target for attacks.
  16. Roman Daniel Says:
    "Asking for the 11th element of a 10-element Perl array causes the array to grow in memory such that the array contains 11 elements, so the request becomes valid."

    I second Karen Etheridge (#8). This is not true. Simple asking is not enough. You either have to set the value at certain index or asked for it in some special context (for example in for statement - for my $el ($x[$big_index]){...})
  17. David Svoboda Says:
    I re-examined the rule (IDS32-PL), and the paragraph you speak of. You're right, merely asking for the value of an invalid array index returns undef, without growing the array.

    You're also correct that arrays can grow just from reading under some circumstances (eg your for example). I extended the code example in IDS32-PL to reflect this.

    The original rule is still correct. And the blog paragraph would be correct if you simply s/ask for/assign to/g :)
  18. David Svoboda Says:
    Next week there will be a webinar about the Source Code Analysis Laboratory (SCALe). We use SCALe for auditing source code in many languages, including Perl, and the need to audit Perl code in SCALe was the impetus for building the CERT Perl Secure Coding standard.
    Details about the webinar and registration are available here:

    http://www.sei.cmu.edu/events/Event-Details.cfm?customel_datapageid_4744=713659&wt.ac=hpWebinar
  19. Yves orton Says:
    I'm a little surprised I haven't heard about this on the perl5 porters mailing list which is the correct place to discuss this material.

    Regarding the rules of creating elements in an array: perils rules for autovivification revolve around distinguishing between lvalue and r value context. Only in lvalue context are items created. The examples you describe differ in terms of context due to things like aliasing of hash items.

    Regarding perls age see perlhist.

    Perls hash function will switch to the supposedly secure sip hash as of 5.18.

    Yves
  20. Andrew Ford Says:
    I presume that the camel on the CERT coding standards home page is used with permission of O'Reilly, as it is their trademark. The Perl community has switched to using an image of an onion as their trademark mascot (see http://www.perlfoundation.org/perl_trademark)
  21. David Svoboda Says:
    Thank you for bringing this up. We've removed the camel temporarily and are asking for the appropriate permission to use it..

Add Comment


Leave this field empty: