Blackbriar's Guide to MOO Security There appears to be some writing on the note ... SECURITY AND RESOURCE ISSUES IN MOOCODE Preface: I write technobabble, so this document is chock full of very dense technical information. Feel free to ask for clarification, if something has been written too confusing. Also, examples given below make minimal use of standards in the Core; for example, .name is used instead of :title or :name or other such verbs. PART I: MOO-CODE SECURITY ========================= There are several different forms of security within the MOO. Some of them include: + Protecting property values from unauthorized access + Protecting verb code from unauthorized access + Authoring verb code such that security breaches do not occur The former topics are better covered in a beginner's course, and so they are neither discussed in detail here, nor will be discussed in the course itself. However, we summarize the different permissions for objects, properties, and verbs: Objects: r - The object is publicly readable. This means that a programmer may use the verbs() and properties() builtins to get a complete list of the verbs and properties defined on the object. This does -not- confer the ability to -read- those verbs and properties; those permissions are handled separately. f - The object is fertile. This means that a builder may create a child of the object, and inherit verb and property definitions. (Properties are inherited as a function of the "c" bit, which is explained shortly. Verb permissions, however, are -not- inherited; a programmer who writes a verb on a parent object needs to bear in mind that calls to that verb will run with the programmer's permission, not that of the child object's owner.) w - The object is publicly writable. This means that a programmer may add or delete verbs or property definitions, at will, to this object. This is, generally speaking, a really bad idea, because it means that the substance of the object cannot be ensured from one minute to the next, as any programmer could change the object at any time. This does -not- imply that anyone can change the contents of verbs or properties on the object; those permissions are handled separately. This -does- imply that anyone could delete verbs and add new verb definitions at any time, although the verbs and properties will be owned by the programmer who does the adding (with the slight exception that properties with the "c" bit set will be added as owned by the object's owner). Properties: r - The property is world-readable. This means that any programmer can directly access the property's value in code (by using the . syntax). To restrict access to a property's contents, the most common method is not to set the "r" bit, and to add a verb with the same name. For example, my .foo property may be !r (meaning that the "r" bit is not set), and so I have a :foo verb which controls access to the property's contents. w - The property is world-writable. This means that any programmer can directly change the property's value (by using the .= syntax). Generally speaking, this is a bad idea, as there'd be no way to control what sort of information is stored in the property, or to ensure that information stored there remains there. A property which is +w and !r remains world-writable, even though programmers could not see the property after they'd written to it. c - The "c" bit is a slightly complicated one, meaning that the property's owner is the same as the object's owner, for children of the object on which the property is defined. Generally speaking, a property should be +c if children's owners are expected to be able to directly modify its value -and- if there is no verb code which changes the property's value. If there is verb code which changes the property's value, there should probably (stylistically speaking) be (using the .foo property again as an example) a :foo verb which controls access, and a :set_foo verb which lets a child set the property's value. [Note to wizards: Properly-constructed verbs will allow you to have and modify +c properties; many examples of this exist for perusal. For example, look at $player.messages and all the mail code which accesses this +c property.] Verbs: r - The verb code is world-readable. As a general rule, this is a good thing. Security via unreadable verbcode is often insufficient. w - The verb code is world-writable. THIS IS AN ALMOST FATAL SECURITY BREACH. If a verb is world-writable, its contents may be changed by any programmer, but its ownership (and thus the permissions under which it will run) will NOT change. This allows nearly complete access to a player and everything e owns, including the ability to reprogram other objects, or destroy them utterly. [Note to wizards: A periodic search for +w verbs is a good thing. Never, ever, under any circumstances, have a wizard-owned verb with this bit set.] x - The verb is callable by other verbs. This will be discussed in more detail in the section titled "Controlling access via location or verb attributes." d - The verb's "debug" bit controls whether the verb terminates with traceback upon hitting an error, or whether it should plod forward and assume the programmer has programmed eir own error-trapping into it. [Author's note: This will be changing, or removed entirely, in the LambdaMOO server version 1.8.0. Happily, that version doesn't even have a speculated release date.] There are several fundamental ways to control security within the MOO. Essentially, these can be boiled down to one of two methods: + Controlling access via location or verb attributes + Controlling access via permissions or caller checks These will be discussed in turn. CONTROLLING ACCESS VIA LOCATION OR VERB ATTRIBUTES -------------------------------------------------- The "x" bit controls whether a verb may be called from another verb. For example, assume I have a note ("note" - #123) with the following verb definition ("read"): note:read this none none rxd that means that the syntax to read that note would be "read note" (or "read #123"). However, the verb is a +x verb, which means that from any verb, whether it's on the note or on some other object, I could include the following line in my programming: #123:read() and that would call the :read verb on my note. (Note that the arguments on the verb are, in this case, irrelevant; if the verb is +x, it will be called regardless of whether the arguments match.) Depending on the programming, it could act precisely as if I'd typed "read note" -- and, although this is perhaps a minor example, it's not difficult to envision this as a larger security risk. If the "x" bit is not set, the verb may only be called from the command-line. This is the simplest, and perhaps most sensible, form of security for purely command-line verbs. For example, the @password command doesn't have an "x" bit set, because @password is intended solely for command-line use. In this case, security can be based on "player" or "caller" -- see a discussion of this later. If the "x" bit is set, the verb may be called from anywhere. This is not necessarily a bad thing, but it means that security ought to be considered. Security here should probably be based on "caller" or "caller_perms()" -- see a discussion of this later. CONTROLLING ACCESS VIA PERMISSIONS OR CALLER CHECKS --------------------------------------------------- CALLER_PERMS() AND SET_TASK_PERMS() ----------------------------------- The caller_perms() builtin will return the permissions of the programmer who called the verb presently executing. If it's the first verb called (i.e. it's the command typed at the command-line), then caller_perms() will be #-1 ($nothing). The permissions of the currently-running verb may be set by a wizard using set_task_perms(). Some illustrations may prove helpful. Let's set up an example: Command-line verb @rename is called by JoePlayer @rename calls :set_name on the object being renamed It's a safe assumption that @rename is wizowned, because only a wizard could change the name of anything arbitrarily. However, if @rename didn't do anything with permissions checks, it would probably allow the player to rename anything at will, even stuff owned by other players. So @rename does a set_task_perms() as follows: set_task_perms(player); and, now, the @rename code begins to run with the permissions of the person who typed the @rename command. (More info on set_task_perms() is given shortly.) Then, when :set_name is called, the caller_perms() are equivalent to those of the player who'd typed in the command, so they can be checked for security. It's also a safe check that :set_name is wizowned, because it's the verb which actually makes the name change. So it has to check the caller's permissions to make sure that the programmer can change the name. Examples of (admittedly bad) verb code could look like: @rename any to any rd Wizard set_task_perms(player); dobj:set_name(iobjstr); set_name this none this rxd Wizard if (caller == this || $perm_utils:controls(caller_pems(), this)) this.name=args[1]; endif; Let's address some issues, bearing in mind that this is a contrived example: + If the @rename verb had been +x, then "player" would not necessarily have been meaningful in the set_task_perms() call -- in fact, this is a very bad security hole, probably one of the more common ways of cracking wizard bits. If a verb has the potential of being a command-line verb -or- called from elsewhere, the syntax should look like: set_task_perms(callers() ? caller_perms() | player); or set_task_perms(valid(caller_perms()) ? caller_perms() | player); where the latter is less CPU-intensive. Both, essentially, say, "Set the task perms to the player who typed the command, if this is being used as a command-line verb, or as the perms being used to call me, if this is being called from elsewhere." Assuming users have not accidentally (purposely?) left security holes, caller_perms() may be safely trusted. + The "caller == this" check is to allow child objects to call this verb; it's standard security, and will be discussed in more detail later. + The "$perm_utils:controls(caller_perms(), this)" call asks whether caller_perms() are equal to the object's owner, or are wizardly. It's also a standard security check. + What if I hadn't wanted to do a security check, if I'd just wanted to let the object crash with traceback if the permissions aren't kosher? In that case, the :set_name verb could have been written as: set_name this none this rxd Wizard set_task_perms(caller_perms()); this.name=args[1]; CALLER ------ In addition to checking permissions, there's also another check that can be done, that using the "caller" variable. The "caller" variable is always set to the object which is calling the verb being executed. For command-line verbs, caller is the same as player. One method of security for command-line verbs is to check caller. (In this case, the player variable could be used just as easily, and in fact -is- used in the following example.) For example, the @rename verb could have started with code like: if (player != this) player:tell("You can't use ", this.name, "'s `", verb, "' command!"); return E_PERM; endif; Another use of caller involves parent objects permitting children access to properties. When combined with permissions checks, these are standard in their forms, and are often used both to set and read properties: if (caller == this || $perm_utils:controls(caller_perms(), this)) "do whatever"; endif; Some objects may be considered "secure". One example of this is #0; the $login object assumes that calls from #0 are secure, and may be trusted. Thus, a verb on $login may look like: $login:connect any none any rxd Wizard if (caller != #0) return E_PERM; endif; Another verb on $login, this one used to transmit information to the disconnected player objects, may look like: $login:notify this none this rx Wizard if (caller == this) notify(player, args[1]); endif; This allows verbs on $login not to be wizowned (as it's a good idea not to use wizardly verbs when they aren't necessary), yet also to be able to effectively use the notify() builtin. It's common to use the "caller == this" check for security. A hypothetical feature object which maintained a list of some sort might want to say that the only way to access the list is to use the feature object itself. So the property would be !r, and the verb to actually access the property would look like: if (caller == this) "do whatever"; endif; PLAYER ------ In general, except for command-line verbs and carefully controlled circumstances, it is a bad idea to use the "player" variable to control security. It is simple (and common) to be able to call verbs with someone else as "player" -- and security based on this variable is often insecure. It's growing increasingly common to attempt to increase the security of "player" by looking at the callers() stack and determining, with near-assurance, who typed the command. However, this makes several bad assumptions. It should be remembered, about player: + While "player" can nearly always be assumed to be the player who typed in the command, that does not necessarily indicate that the verbs being called are in any way related to the command that was typed. + Programmers may reset the value of "player" within their programming, and within that one specific verb call the value will be changed, but all further verb calls will use the correct value of the variable; it is not, in fact, changed. However, wizards -can- change the value of "player" (this is done with great effectiveness with LambdaMOO's generic puppet). CALLERS() --------- The callers() stack may be traced to see the sequence of verb calls which led to the verb being executed. It may be depended on, for what it's worth, with the following notes: + Using callers() is very CPU-intensive. The most useful security information can nearly always be obtained by looking at caller_perms() or caller. + Tasks which are initiated by a fork() call get their own, fresh, callers() stack, which do -not- trace sequences which initiated the fork. [There is a bit at the end of the most recent version -- which is in my office which is not on the net -- which discusses the use of clear properties in security. Part II of this document, which discusses MOO resource usage, is unfinished, but will be posted once I finish it.] Seth / Blackbriar (You finish reading.)