I realize that I’ve spent a lot of time explaining best practices and what my recommendations are, but I don’t often explain why some settings aren’t the best.
Some of my favorite magazines will describe a popular action and then explain why that practice is not so bad, pretty bad, or really bad. Using this method, I’m going to describe how bad certain security settings are.
QCRTAUT is the system value that sets the *PUBLIC authority when an object is created. IBM ships this value at *CHANGE. While it’s best practice to set this value to *EXCLUDE or *USE, I’m OK with it being left at *CHANGE as long as you set the Create authority value of all libraries containing data to *USE or *EXCLUDE. If I set QCRTAUT to *USE or *EXCLUDE, I generally set the Create authority value of vendor libraries to be *CHANGE, since they tested their code with QCRTAUT set to *CHANGE. So whether you set your data libraries’ Create authority attribute to *EXCLUDE and leave the system value at *CHANGE or set QCRTAUT to *EXCLUDE and change the vendor libraries, it accomplishes the same thing.
How bad is QCRTAUT set to *CHANGE? Not so bad.
However, it’s a different story when the QCRTAUT value has been set to *ALL. I cringe whenever we do a risk assessment and find QCRTAUT set to *ALL. That’s because it’s very difficult to predict what will fail when you change it. Even setting it back to the default of *CHANGE can cause failures. For example, processes that perform an Add Physical File Member (ADDPFM) need to have *CHANGE plus *OBJMGT to the *FILE. Same with Create Duplicate Object (CRTDUPOBJ). Clearing a physical file requires *OBJEXIST to the *FILE. So while you may think the only thing you’re preventing is the deletion of objects when you change QCRTAUT from *ALL back to *CHANGE, you may actually be preventing tasks that you may think should only require *CHANGE but actually require more.
How bad is it when QCRTAUT is set to *ALL? Really bad!
QSECURITY is the system value that sets the “tone” or security level of the system. While you may think that I’ll say that security level 20 is really bad and 30 is not so bad, you may be surprised. At security level 20, all users are—by default—created with *ALLOBJ and *SAVSYS special authorities. Because the same authority-checking algorithm is run at both levels, you can remove the *ALLOBJ special authority from non-administrator profiles and have a system that runs, essentially, like it’s set to QSECURITY = 30. The problem with running at a security level less than 40 is that you don’t have operating system integrity and you can easily run as a different profile, with the possibility of elevating your privileges to a very powerful profile (as in a profile with all special authorities). This is done by using a Job description (*JOBD) that specifies a user profile. At security level 20 and 30, I only need authority to the *JOBD, not the profile specified in the job description. Many vendors ship *JOBDs with their products, often naming a powerful profile. All I have to do is run a remote command, submitting a job using one of these *JOBDs, and I’ve elevated to a powerful profile. This cannot be prevented at level 20 and 30; however, it is inherently prevented at level 40 and above. (At level 40 and above, I have to have authority to both the *JOBD and the user profile named in the *JOBD.)
How bad is running at either security level 20 or 30? Really bad!
This system value sets the object auditing value when a new object is created. Setting the object auditing value to *ALL causes an audit journal entry to be generated every time the object is either read (a ZR entry) or updated (a ZC entry). This may sound like a best-practice setting, but before you set this system value to *ALL, you need to consider all of the objects being created on your system. Think of all of the data areas, user spaces, user queues, user indexes, database files, and other objects that are being read and updated on your system and how often that happens! Setting QCRTOBJAUD to *ALL tends to flood systems (as in, consume massive amounts of storage) with ZR and ZC entries because of temporary objects being deleted and recreated and read or updated multiple times in between. If you need to monitor when objects are both read and updated, a better approach is to either set the Create object audit value for the library the objects are being created into or be even more granular and run the Change Object Auditing (CHGOBJAUD) command to set the auditing value on a specific object or for all of the *FILEs in a particular library, for example. If you insist on changing the setting for the QCRTOBJAUD system value to something other than the shipped value of *NONE, choose *CHANGE. It’s typically the reads that consume the system storage. Auditing for updates only may be manageable from a system storage perspective.
How bad is setting QCRTOBJAUD to *ALL? Pretty bad!
I’m a big fan of authorization lists, especially when setting access controls for *FILEs. It allows me to grant access to many files (and other objects) all at once. I simply attach the authorization list to the objects and then grant users authority to the list. Whatever authority the users have to the authorization list, that’s the authority they have to the objects secured by the list.
The trick comes with setting *PUBLIC authority. When an object is secured with an authorization list, the object’s *PUBLIC authority can come either from the object itself or from the authorization list. My preference is to have it come from the authorization list. (To accomplish that, set *PUBLIC to *AUTL.) I especially want to do that when I’m working with a client and we’re reworking the security scheme of their application. At some point, we typically want to set all database files to be *PUBLIC *EXCLUDE. When all of the objects have been set to *PUBLIC(*AUTL), that’s easy to accomplish. Simply set the *PUBLIC authority of the authorization list to *EXCLUDE. If you don’t take that approach, you must go to each object and set the *PUBLIC authority on each object. That can be difficult, especially if the objects are *FILEs and the *FILEs are in use. I also like to set it on the authorization list to avoid confusion. If the object’s *PUBLIC authority is one value (say, *USE) and the authorization lists’ *PUBLIC authority is *CHANGE, which one does the system use? The answer is the object’s, but it’s easier if the setting just comes from the authorization list! Setting *PUBLIC authority on the authorization list also means that all authorities are coming from one place, so I don’t have to look at both the list and the object itself when trying to debug authority issues.
How bad is it when *PUBLIC authority comes from the object? Not so bad (just inconvenient and potentially confusing!).
Service Account Configuration
Most organizations have one or more profiles I refer to as “service accounts.” These are the profiles that don’t represent people. Rather, they run processes, often connecting to the system from other servers via FTP or ODBC. Most of you know to configure these service accounts to not allow signon—that is, set the Initial program (INLPGM) to *NONE and Initial menu (INLMNU) to *SIGNOFF. But it’s rare that I see the final step taken: setting the Attention program (ATNPGM) to *NONE. I can hear you saying, “But you can’t sign on to a 5250 emulation session with these settings.” True...except if you enter the user ID and password for the service account and press the Attention key when you get the message that the profile can’t sign on. If you press the Attention key quickly enough, you are taken to the Attention menu! Depending on the options on the Attention menu, and if you haven’t set the service account profile to LMTCPB(*YES), the profile may be used to enter commands and access data. When my team performs penetration testing for IBM i, we look for this scenario. When a service account has a default password (which is often the case), we are usually able to access data in this very unexpected way.
How bad is it to not set service accounts to best-practice settings? Pretty bad.
QPWDLVL is the system value that sets the password level for the system. Leaving the system at the default of QPWDLVL = 0 exposes your enterprise to allowing a very weakly hashed version of the password that’s stored at level 0 or 2 to be exploited. This version of the password is only used by old clients. By “old,” I mean Windows 95, 98, and ME and Windows 2000 server. Hopefully, none of you are still using this technology. Or, if you are, you aren’t using these operating systems to map a drive to access the IBM i NetServer. Assuming this is the case, you can safely move up to either password level 1 (if running at 0) or password level 3 (if the system is currently running at 2.) For more information on moving to a higher password level, read this article.
How bad is running at password levels 0 or 2? Pretty bad.
QMAXSIGN is the system value that controls how many times people can guess their password before some action is taken. Setting this system value to *NOMAX means that users are allowed to try forever to try to get the right combination. While this might be OK when users are trying to log on with their own password, it’s not OK when someone is trying to sign on with a profile other than their own, or a hacker has entered your network, or an insider is trying to exploit someone else’s profile. Best-practice range for this value is 3–5, and the recommended action to take when the limit is reached is to disable the profile or disable the profile and the device being used.
How bad is it when QMAXSIGN is set to *NOMAX? Really bad!
I hope this discussion has been a fun way to provide perspective on why some settings are better than others.