2

This question is specifically focused around static libraries / frameworks; in other words, code that other people will eventually touch.

I'm fairly well versed in properties, since I started iOS development when iOS 6 was released. I have used hidden properties declared in interface extensions to do all of my "private" property work, including using readonly on public facing properties I don't want others to modify and readwrite within interface extensions.

The important thing is that I do not want other people who are using these static libraries / frameworks to be accessing these properties if I don't allow it, nor writing these properties if I let them read it.

I've known for a while that they could theoretically create their own interface extension and make my readonly properties readwrite themselves, or guess the names of hidden properties.

If I want to prevent this, should I be using ivars with the @private tag with directly declared ivars? Are there potential downfalls to doing it this way? Does it actually get me an additional measure of security, or is it a red herring?

Joel Fischer
  • 6,521
  • 5
  • 35
  • 46
  • You cannot prevent the property from being accessed at runtime. Compare http://stackoverflow.com/questions/4777165/private-and-protected-methods-in-objective-c. – Martin R Dec 18 '13 at 23:08
  • I'm well aware that with the power of the Obj-C runtime comes some security "risks". I'm more thinking of the casual hacker than the thoroughly dedicated one. – Joel Fischer Dec 18 '13 at 23:19

2 Answers2

4

Under ARC the only mode supported by properties and not instance variables is copy - so if you need copy use a property.

If you declare your private instance variables in the @implementation section:

@implementation MyClass
{
   // private instance vars
}

then it takes serious effort to access them from outside the class. As you say accessing a "private" property just takes guessing its name - or using the library calls which tell you.

Is it worth it for security? YMMV. But its a good coding practice regardless.

Addendum

As the comment trail shows there has been much discussion over my use of serious effort.

First let's be clear: Objective-C is in the C family of languages, they all allow the programmer to just about anything they choose while staying within the language[*] - these are not the languages of choice if you want strong typing, access restrictions, etc., etc. within your code.

Second, "effort" is not an absolute measure! So maybe I should have chosen the word "obvious" to qualify it rather than "serious". To access a private property just requires the use of a standard method call where the object has type id - there is little clue in the code that the method being called is hidden. To access a private variable requires either an API call (a runtime function or KVC call) or some pointer manipulation - the resultant code looks nothing like a standard variable assignment. So its more obvious.

That said, apart from uses requiring copy, under ARC there is no good reason to use a private property when a private instance variable will do. For a private variable fred compare:

self.fred = 42;   // property access, may involve a call (if not optimised out)
_fred = 42;       // common way to bypass the accessors and get at the underlying var
fred = 42;        // direct access

Take your pick, there is no right answer, but there isn't a wrong one either - this is the realm of opinion (and that is of course an opinion ;-)). I would often pick the last one, private variable - clean & simple. However @RobNapier in his answer prefers the use of properties.


[*] Note: once you consider linking to external code, say written in assembler, all bets are of in any language. At that point you have to look at the "hardware" (real or virtual) and/or "OS" to provide protection.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • Can you clarify 'serious effort' for me? Are we talking about objc runtime calls that could be made in code to pull them out and modify them? I realize that Obj-C isn't a particularly secure language, so I guess I'm asking for clarification on just how much effort is involved. – Joel Fischer Dec 18 '13 at 23:23
  • 1
    @JoelFischer - A few runtime functions, disable ARC, a cast or two. But as yo say, it's (Obj-)C so anything is possible. If you want language support for secure code don't use one based on C! – CRD Dec 18 '13 at 23:54
  • @CRD Not so sure about the 'serious effort' given that a simple KVC call can modify any ivar. – jlehr Dec 18 '13 at 23:57
  • @jlehr But assuming you take his advice and declare them in the implementation block, then 'serious effort' becomes nuking `class_copyIvarList()` – CodaFi Dec 19 '13 at 01:31
  • @CodaFi may not be fully clear here. The point is that class_copyIvarList() will give you the list of ivars (including their names and types). Accessing them is as easy as object_getInstanceVariable(). It takes about 45 seconds longer than accessing your "hidden" property. There's no win here. – Rob Napier Dec 19 '13 at 02:10
  • And to @jlehr's excellent point, once they've pulled your list of ivars, `valueForKey:` and `setValueForKey:` will helpfully access your ivars directly (you can turn that off by overriding `accessInstanceVariablesDirectly`, but again, that just means they have to call object_getInstanceVariable. Not exactly a firewall. – Rob Napier Dec 19 '13 at 02:12
2

You should use private ("hidden") properties here. There is no "security" risk. The "attacker" in this scenario is the caller. The caller has complete access to all memory in the process. She can access anything in your framework she wants and there is absolutely nothing you can do to stop that (nor should you). This is true in any language. You can bypass "private:" designations in C++ as well if you know what you're doing. It's all just memory at the end of the day.

It is not your job to protect yourself or your framework from the caller. You both have the same goal: correct program behavior. Your goal is to protect callers from themselves. Make it difficult for them to use your framework incorrectly and easy to use it correctly.

So, you should use the tool that leads to the most correct code. And that tool is properties, and avoiding directly ivar access except in init and dealloc.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Let's presume that this code isn't open-source, and is proprietary and covered under licensing agreements. I realize that nothing is secure in Objective-C, but it still benefits the company to keep things relatively secure from casual hacks. Based on what you (and others) are saying it sounds like private ivars is indeed more secure, but certainly not secure from an interpid hacker. So it becomes a "slightly more secure" vs. "certainly more correct". – Joel Fischer Dec 19 '13 at 01:50
  • 1
    You may be interested in previous discussions: http://stackoverflow.com/questions/2334072/decompiling-objective-c-libraries. Hiding your code from someone you ship it to is a losing game and a money sink. Focus on making it better code that is cheaper to maintain. Direct ivar access is not going to provide you any useful security against someone with your library, but it is going to introduce bugs you will then have to spend money and goodwill to solve. – Rob Napier Dec 19 '13 at 02:03
  • 1
    @RobNapier - Assuming ARC, for *private* "variables", excluding the `copy` option for properties, can you summarise why in your opinion the choice "is properties, and avoiding directly ivar access except in init and dealloc"? Just curious. – CRD Dec 19 '13 at 17:24
  • @CRD, see http://stackoverflow.com/a/15644838/97337 for one of my discussions on this. It comes down to maintainability. Direct ivar access makes it very hard to verify code correctness in the presence of anything that actually needs an accessor (which is quite common). copy is just one of several patterns. But copy is a good example. How do you audit against a rule that says "use ivars except if the property is `copy`?" How do you keep track of which are which? Requiring the developer to check the header file for every line of code is a sure path to bugs. Consistency protects us. – Rob Napier Dec 19 '13 at 18:34
  • @RobNapier - Thanks. I understand your argument, though I may not agree with it ;-) But that is another issue for another time. – CRD Dec 19 '13 at 19:37