Do you use friend to avoid security problems ?

Started by
20 comments, last by Hodgman 8 years, 6 months ago

I honestly think private/protected are worthless features in C++. They serve some purpose in module-based languages like Java or C#, but their basic use in C++ is just not particularly compelling.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Advertisement


If you're truly concerned with security, that is, you want to prevent malicious users of your API from doing things that could be harmful to other users or to you, then making functions private will do very little to help you achieve your goals of protection. If a malicious person wants to call a private function, they only need to discover its existence, find its location in the executable, determine the proper calling convention and parameters, and then they can freely call it with whatever parameter values they want. While the above steps aren't trivial, especially for your average script kiddie, for a well practiced malicious agent it's not that hard.

If you're using protected/private to try to 'secure' an API, it'd be even more trivial for a user just to add the following lines before including your headers:

#define protected public

#define private public

And they will have access to all the innards of your classes as if they had the friend designation.

It's probably best to think of protected and private as mechanisms to encourage and simplify correct use of your API rather than to prevent misuse.

#define protected public
#define private public

Good catch.

I honestly think private/protected are worthless features in C++. They serve some purpose in module-based languages like Java or C#, but their basic use in C++ is just not particularly compelling.


Private is very important in that it lets you provide a clean API to end users that allow you to modify the internals with minimal recompilation and preserve class invariants. Protected has a few useful applications (for holding an interface's destructor for example if you don't want someone destroying an object via the interface).

Like others have said, access semantics, like other things in the language, are there to protect the programmer from making mistakes and to help enforce good code design, not to actually make your code secure from attacks. The CPU of course does not see these access semantics.

The primary goal of the post is to secure the end user of the API but the part about attacks was not bad.

EDIT because of language mistakes :

The primary goal of the post is about security for the end user of the API but the part about attacks was not bad.


Private is very important in that it lets you provide a clean API to end users that allow you to modify the internals with minimal recompilation and preserve class invariants. Protected has a few useful applications (for holding an interface's destructor for example if you don't want someone destroying an object via the interface).

Except we're talking about C++, which immediately and catastrophically fucks this up by making the private internals part of the header anyway. So then we end up with tricks ranging from vanilla polymorphic interfaces to pImpl idiom variations, rendering the whole exercise pointless.


Like others have said, access semantics, like other things in the language, are there to protect the programmer from making mistakes and to help enforce good code design

And the moment you inflict friend, we're not talking about good code design anymore, we're talking about continuing hacks where the core design has already gone awry. It's worth noting that a number of modern languages get by just fine without access semantics. My argument is they may get along better without them and that the very use of access semantics represents total failure of encapsulation in C++. Why? Because even if I can't access the internal details of a class, I can see them just fine due to other encapsulation-puncturing issues in the language. That serves to bind clients to implementation details anyway, in the absence of pImpl type techniques. Lacking the relevant semantics forces you to deal with the interface/implementation divide directly. This is not the case in Java or C#, which implement sane module systems and let you alter implementations without impacting clients.

If you consider C++ private/protected semantics relevant to your code design, it's time for a redesign.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

Private is very important in that it lets you provide a clean API to end users that allow you to modify the internals with minimal recompilation and preserve class invariants. Protected has a few useful applications (for holding an interface's destructor for example if you don't want someone destroying an object via the interface).

Except we're talking about C++, which immediately and catastrophically fucks this up by making the private internals part of the header anyway. So then we end up with tricks ranging from vanilla polymorphic interfaces to pImpl idiom variations, rendering the whole exercise pointless.

Pointless? Hardly. Just because you CAN get around something doesn't make it pointless. In most cases, getting around a properly designed interface's boundaries not only causes compiler warnings, but just plain looks wrong.

I mean, as long as you're complaining about implementation in headers, you might as well also complain about templates which force implementation in headers. Or the fact that the compiler sees all your code anyway via link-time code generation and optimizations.

At this point you're not complaining about public/private/protected, you're just complaining about the header and compilation unit system which has long outgrown its usefulness and is being replaced with proper modules in a future C++ version once they nail down the spec.

Like others have said, access semantics, like other things in the language, are there to protect the programmer from making mistakes and to help enforce good code design

And the moment you inflict friend, we're not talking about good code design anymore, we're talking about continuing hacks where the core design has already gone awry. It's worth noting that a number of modern languages get by just fine without access semantics. My argument is they may get along better without them and that the very use of access semantics represents total failure of encapsulation in C++. Why? Because even if I can't access the internal details of a class, I can see them just fine due to other encapsulation-puncturing issues in the language. That serves to bind clients to implementation details anyway, in the absence of pImpl type techniques. Lacking the relevant semantics forces you to deal with the interface/implementation divide directly. This is not the case in Java or C#, which implement sane module systems and let you alter implementations without impacting clients.

If you consider C++ private/protected semantics relevant to your code design, it's time for a redesign.


I never talked about friend intentionally, because I don't think it's that useful and tends to cause the problems you list.

But again, the mere presence of a language feature doesn't completely invalidate other language features.

Heck, the C# and Java code that love so much requires you to put interface and implementation in the same file. You can't even hide your code in the same way the C header/source system does. The only time you don't see the entire implementation is when you are dealing with a library and only have the compiled metadata to go against.

I mean, as long as you're complaining about implementation in headers, you might as well also complain about templates which force implementation in headers.

"As long as we're complaining about Alzheimer's, we might as well also complain about cancer."


At this point you're not complaining about public/private/protected, you're just complaining about the header and compilation unit system which has long outgrown its usefulness and is being replaced with proper modules in a future C++ version once they nail down the spec.

Just to be clear, my claim is that private/protected semantics have no value in C++ as it exists today. Yes, the compilation model got us here. But as long as we're living with that, I simply reject any idea that these features accomplish anything but a false feel-good sense of "ah, totally encapsulated". Encapsulation in C++ requires polymorphic interfaces or pImpl, period. (Or in some cases, stripped headers, which are a messy game to play.) Once you apply these techniques, access semantics no longer have any meaning anyway.


Heck, the C# and Java code that love so much requires you to put interface and implementation in the same file. You can't even hide your code in the same way the C header/source system does. The only time you don't see the entire implementation is when you are dealing with a library and only have the compiled metadata to go against.

I've seen this complaint many times over the years - there is no file in these languages that sums up the public interface without the implementation details, unless of course you write up a polymorphic interface and implement it separately. The ability to see the public interface is instead consigned to IDE based metadata or code analysis tools. I have mixed feelings about this. But in the course of practical and professional work, the C++ version has created far more problems for me while the C# version is inconvenient at worst. Of course this leads back to the C++ compilation model, which is a disease that goes far beyond something as trivial as private/protected.

At the end of the day, I can't think of an instance across 15 years of personal and professional C++ development work where I've avoided a single bug or mistake by marking variables as private. The borderline cases are easily dealt with by naming convention. Since client code is bound by the compilation model to the total definition of the class anyway, you just don't get the expected benefits.

The primary goal of the post is to secure the end user of the API but the part about attacks was not bad.

No idea what you're talking about.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
No idea what you're talking about.

I edited the post because of the language mistakes :

"The primary goal of the post is about security for the end user of the API but the part about attacks was not bad."


Just to be clear, my claim is that private/protected semantics have no value in C++ as it exists today.
...but it's still standard practice to use private extensively in code today, as it does provide a lot of benefit...

This topic is closed to new replies.

Advertisement