{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/corefx/issues/3025","labels_url":"https://api.github.com/repos/dotnet/corefx/issues/3025/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/3025/comments","events_url":"https://api.github.com/repos/dotnet/corefx/issues/3025/events","html_url":"https://github.com/dotnet/corefx/issues/3025","id":103972272,"number":3025,"title":"SecureException proposal","user":{"login":"OtherCrashOverride","id":3499273,"avatar_url":"https://avatars.githubusercontent.com/u/3499273?v=3","gravatar_id":"","url":"https://api.github.com/users/OtherCrashOverride","html_url":"https://github.com/OtherCrashOverride","followers_url":"https://api.github.com/users/OtherCrashOverride/followers","following_url":"https://api.github.com/users/OtherCrashOverride/following{/other_user}","gists_url":"https://api.github.com/users/OtherCrashOverride/gists{/gist_id}","starred_url":"https://api.github.com/users/OtherCrashOverride/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OtherCrashOverride/subscriptions","organizations_url":"https://api.github.com/users/OtherCrashOverride/orgs","repos_url":"https://api.github.com/users/OtherCrashOverride/repos","events_url":"https://api.github.com/users/OtherCrashOverride/events{/privacy}","received_events_url":"https://api.github.com/users/OtherCrashOverride/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/corefx/labels/api%20addition","name":"api addition","color":"207de5"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":48,"created_at":"2015-08-31T02:01:40Z","updated_at":"2015-08-31T21:18:35Z","closed_at":null,"body":"Current exceptions are prone to unintentionally leaking potentially sensitive information.  This proposal establishes a clear separation between what is a diagnostic message and what is diagnostic data.\r\n\r\n# Rationale and Usage\r\nSecurity is a paramount concern for modern developers.  There is increasing pressure on developers to meet company security demands as well as legal security requirements.  Exceptions messages are often logged.  It should be easier for developers to protect potentially sensitive information contained in those messages while still offering unprotected diagnostic messages.\r\n\r\n# Proposed API\r\n```\r\n    public partial class Exception\r\n    {\r\n        public virtual string PrivateMessage\r\n        {\r\n            get { return \"No additional information provided.\"; }\r\n        }\r\n    }\r\n\r\n\r\n    public abstract class SecureException : Exception\r\n    {\r\n        public override string PrivateMessage\r\n        {\r\n            get\r\n            {\r\n                if (PAL_GetDetailedExceptionInfoFeatureEnabledFlag())\r\n                {\r\n                    return GetPrivateMessage();\r\n                }\r\n                else\r\n                {\r\n                    return \"Feature not enabled.\";\r\n                }\r\n            }\r\n        }\r\n\r\n\r\n\r\n        protected SecureException(string publicMessage)\r\n            : base(publicMessage)\r\n        {\r\n        }\r\n\r\n\r\n        protected abstract string GetPrivateMessage();\r\n\r\n\r\n        static bool PAL_GetDetailedExceptionInfoFeatureEnabledFlag()\r\n        {\r\n            // TODO: Read feature flag from runtime\r\n            return true;\r\n        }\r\n    }\r\n\r\n\r\n    public class DuplicateKeyException : SecureException\r\n    {\r\n        const string EXCEPTION_MESSAGE = \"An item with the same key has already been added.\";\r\n\r\n\r\n        object key;\r\n\r\n        public object Key\r\n        {\r\n            // Note: The concern here is serialization.\r\n            // The goal is to prevent accidental leakage and\r\n            // serialization implies intent so this value should\r\n            // not be occluded.\r\n            get { return key; }\r\n        }\r\n\r\n\r\n        public DuplicateKeyException(object key)\r\n            : base(EXCEPTION_MESSAGE)\r\n        {\r\n            this.key = key;\r\n        }\r\n\r\n\r\n        protected override string GetPrivateMessage()\r\n        {\r\n            // Note: ArgumentNullException is throw instead if a key is null\r\n\r\n            string result;\r\n\r\n            if (key == null)\r\n            {\r\n                result = string.Empty;\r\n            }\r\n            else\r\n            {\r\n                if (key.GetType().IsValueType)\r\n                {\r\n                    result = string.Format(\"The key '{0}' is duplicated\", key.ToString());\r\n                }\r\n                else\r\n                {\r\n                    result = string.Format(\"The key is an object of type {0}.\", key.GetType().ToString());\r\n                }\r\n            }\r\n\r\n            return result;\r\n        }\r\n    }\r\n\r\n\r\n    public class FileNotFoundException : SecureException\r\n    {\r\n        const string EXCEPTION_MESSAGE = \"Unable to find the specified file.\";\r\n\r\n\r\n        string fileName;\r\n\r\n        public string FileName\r\n        {\r\n            get { return fileName; }\r\n        }\r\n\r\n\r\n        public FileNotFoundException(string fileName)\r\n            : base (EXCEPTION_MESSAGE)\r\n        {\r\n        }\r\n\r\n\r\n        protected override string GetPrivateMessage()\r\n        {\r\n            return string.Format(\"Could not find file '{0}'\", fileName);\r\n        }\r\n    }\r\n\r\n\r\n    public class SimpleSecureException : SecureException\r\n    {\r\n        string privateMessage;\r\n\r\n        public SimpleSecureException(string publicMessage, string privateMessage)\r\n            : base(publicMessage)\r\n        {\r\n            this.privateMessage = privateMessage;\r\n        }\r\n\r\n        protected override string GetPrivateMessage()\r\n        {\r\n            return privateMessage;\r\n        }\r\n    }\r\n```\r\n\r\n# Details\r\n* Only constant strings are used in the public exception message\r\n* PrivateMessage logic is only activated when read. If it is never read, code for it never runs. resources are never consumed for it and there are no side-effects of its use.\r\n* PrivateMessage provides as much information that makes sense in the context of the exception while avoiding over stating information.\r\n* DetailedExceptionInfoFeature flag that is passed to the runtime during creation by the host. How the host determines to enable it (environment variable, command line option, registry entry) is entirely host dependent. The flag is part of the hosting API and defaults to disabled if not explicitly enabled. It can only be specified during host creation and is immutable."},"comment":{"url":"https://api.github.com/repos/dotnet/corefx/issues/comments/136504721","html_url":"https://github.com/dotnet/corefx/issues/3025#issuecomment-136504721","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/3025","id":136504721,"user":{"login":"OtherCrashOverride","id":3499273,"avatar_url":"https://avatars.githubusercontent.com/u/3499273?v=3","gravatar_id":"","url":"https://api.github.com/users/OtherCrashOverride","html_url":"https://github.com/OtherCrashOverride","followers_url":"https://api.github.com/users/OtherCrashOverride/followers","following_url":"https://api.github.com/users/OtherCrashOverride/following{/other_user}","gists_url":"https://api.github.com/users/OtherCrashOverride/gists{/gist_id}","starred_url":"https://api.github.com/users/OtherCrashOverride/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OtherCrashOverride/subscriptions","organizations_url":"https://api.github.com/users/OtherCrashOverride/orgs","repos_url":"https://api.github.com/users/OtherCrashOverride/repos","events_url":"https://api.github.com/users/OtherCrashOverride/events{/privacy}","received_events_url":"https://api.github.com/users/OtherCrashOverride/received_events","type":"User","site_admin":false},"created_at":"2015-08-31T21:18:35Z","updated_at":"2015-08-31T21:18:35Z","body":"> And that all standard exception types base off that type\r\nYes, everything in CoreCLR and CoreFX should be rebased to SecureException.  Developers are not required to change any of their code if they so choose."}}